summaryrefslogtreecommitdiff
path: root/src/strife
diff options
context:
space:
mode:
Diffstat (limited to 'src/strife')
-rw-r--r--src/strife/.gitignore5
-rw-r--r--src/strife/Makefile.am78
-rw-r--r--src/strife/am_map.c1391
-rw-r--r--src/strife/am_map.h57
-rw-r--r--src/strife/d_englsh.h600
-rw-r--r--src/strife/d_items.c167
-rw-r--r--src/strife/d_items.h50
-rw-r--r--src/strife/d_main.c2000
-rw-r--r--src/strife/d_main.h64
-rw-r--r--src/strife/d_net.c316
-rw-r--r--src/strife/d_player.h257
-rw-r--r--src/strife/d_textur.h51
-rw-r--r--src/strife/d_think.h76
-rw-r--r--src/strife/deh_ammo.c112
-rw-r--r--src/strife/deh_cheat.c157
-rw-r--r--src/strife/deh_frame.c168
-rw-r--r--src/strife/deh_misc.c237
-rw-r--r--src/strife/deh_misc.h92
-rw-r--r--src/strife/deh_ptr.c151
-rw-r--r--src/strife/deh_sound.c112
-rw-r--r--src/strife/deh_strife.c74
-rw-r--r--src/strife/deh_thing.c141
-rw-r--r--src/strife/deh_weapon.c111
-rw-r--r--src/strife/doomdata.h233
-rw-r--r--src/strife/doomdef.c36
-rw-r--r--src/strife/doomdef.h299
-rw-r--r--src/strife/doomstat.c43
-rw-r--r--src/strife/doomstat.h286
-rw-r--r--src/strife/dstrings.c81
-rw-r--r--src/strife/dstrings.h49
-rw-r--r--src/strife/f_finale.c1056
-rw-r--r--src/strife/f_finale.h56
-rw-r--r--src/strife/f_wipe.c300
-rw-r--r--src/strife/f_wipe.h71
-rw-r--r--src/strife/g_game.c2456
-rw-r--r--src/strife/g_game.h97
-rw-r--r--src/strife/hu_lib.c482
-rw-r--r--src/strife/hu_lib.h193
-rw-r--r--src/strife/hu_stuff.c666
-rw-r--r--src/strife/hu_stuff.h75
-rw-r--r--src/strife/info.c11049
-rw-r--r--src/strife/info.h2227
-rw-r--r--src/strife/m_menu.c2377
-rw-r--r--src/strife/m_menu.h109
-rw-r--r--src/strife/m_random.c88
-rw-r--r--src/strife/m_random.h47
-rw-r--r--src/strife/m_saves.c538
-rw-r--r--src/strife/m_saves.h64
-rw-r--r--src/strife/p_ceilng.c351
-rw-r--r--src/strife/p_dialog.c1420
-rw-r--r--src/strife/p_dialog.h108
-rw-r--r--src/strife/p_doors.c1378
-rw-r--r--src/strife/p_enemy.c3373
-rw-r--r--src/strife/p_floor.c590
-rw-r--r--src/strife/p_inter.c1408
-rw-r--r--src/strife/p_inter.h40
-rw-r--r--src/strife/p_lights.c380
-rw-r--r--src/strife/p_local.h309
-rw-r--r--src/strife/p_map.c1655
-rw-r--r--src/strife/p_maputl.c1061
-rw-r--r--src/strife/p_mobj.c1352
-rw-r--r--src/strife/p_mobj.h338
-rw-r--r--src/strife/p_plats.c362
-rw-r--r--src/strife/p_pspr.c1012
-rw-r--r--src/strife/p_pspr.h87
-rw-r--r--src/strife/p_saveg.c2215
-rw-r--r--src/strife/p_saveg.h70
-rw-r--r--src/strife/p_setup.c865
-rw-r--r--src/strife/p_setup.h45
-rw-r--r--src/strife/p_sight.c368
-rw-r--r--src/strife/p_spec.c1996
-rw-r--r--src/strife/p_spec.h686
-rw-r--r--src/strife/p_switch.c1082
-rw-r--r--src/strife/p_telept.c160
-rw-r--r--src/strife/p_tick.c165
-rw-r--r--src/strife/p_tick.h41
-rw-r--r--src/strife/p_user.c922
-rw-r--r--src/strife/r_bsp.c581
-rw-r--r--src/strife/r_bsp.h69
-rw-r--r--src/strife/r_data.c1026
-rw-r--r--src/strife/r_data.h61
-rw-r--r--src/strife/r_defs.h456
-rw-r--r--src/strife/r_draw.c976
-rw-r--r--src/strife/r_draw.h119
-rw-r--r--src/strife/r_local.h53
-rw-r--r--src/strife/r_main.c953
-rw-r--r--src/strife/r_main.h168
-rw-r--r--src/strife/r_plane.c455
-rw-r--r--src/strife/r_plane.h84
-rw-r--r--src/strife/r_segs.c762
-rw-r--r--src/strife/r_segs.h41
-rw-r--r--src/strife/r_sky.c62
-rw-r--r--src/strife/r_sky.h45
-rw-r--r--src/strife/r_state.h135
-rw-r--r--src/strife/r_things.c1065
-rw-r--r--src/strife/r_things.h74
-rw-r--r--src/strife/s_sound.c828
-rw-r--r--src/strife/s_sound.h103
-rw-r--r--src/strife/sounds.c235
-rw-r--r--src/strife/sounds.h230
-rw-r--r--src/strife/st_lib.c340
-rw-r--r--src/strife/st_lib.h229
-rw-r--r--src/strife/st_stuff.c1555
-rw-r--r--src/strife/st_stuff.h108
-rw-r--r--src/strife/wi_stuff.c1844
-rw-r--r--src/strife/wi_stuff.h59
106 files changed, 66000 insertions, 0 deletions
diff --git a/src/strife/.gitignore b/src/strife/.gitignore
new file mode 100644
index 00000000..d4e88e5a
--- /dev/null
+++ b/src/strife/.gitignore
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+.deps
+tags
+TAGS
diff --git a/src/strife/Makefile.am b/src/strife/Makefile.am
new file mode 100644
index 00000000..df1f7bb0
--- /dev/null
+++ b/src/strife/Makefile.am
@@ -0,0 +1,78 @@
+AM_CFLAGS = -I.. @SDL_CFLAGS@ @SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
+
+noinst_LIBRARIES=libstrife.a
+
+SOURCE_FILES= \
+am_map.c am_map.h \
+ d_englsh.h \
+d_items.c d_items.h \
+d_main.c d_main.h \
+d_net.c \
+ doomdata.h \
+doomdef.c doomdef.h \
+doomstat.c doomstat.h \
+ d_player.h \
+dstrings.c dstrings.h \
+ d_textur.h \
+ d_think.h \
+f_finale.c f_finale.h \
+f_wipe.c f_wipe.h \
+g_game.c g_game.h \
+hu_lib.c hu_lib.h \
+hu_stuff.c hu_stuff.h \
+info.c info.h \
+m_menu.c m_menu.h \
+m_random.c m_random.h \
+m_saves.c m_saves.h \
+p_ceilng.c \
+p_dialog.c p_dialog.h \
+p_doors.c \
+p_enemy.c \
+p_floor.c \
+p_inter.c p_inter.h \
+p_lights.c \
+ p_local.h \
+p_map.c \
+p_maputl.c \
+p_mobj.c p_mobj.h \
+p_plats.c \
+p_pspr.c p_pspr.h \
+p_saveg.c p_saveg.h \
+p_setup.c p_setup.h \
+p_sight.c \
+p_spec.c p_spec.h \
+p_switch.c \
+p_telept.c \
+p_tick.c p_tick.h \
+p_user.c \
+r_bsp.c r_bsp.h \
+r_data.c r_data.h \
+ r_defs.h \
+r_draw.c r_draw.h \
+ r_local.h \
+r_main.c r_main.h \
+r_plane.c r_plane.h \
+r_segs.c r_segs.h \
+r_sky.c r_sky.h \
+ r_state.h \
+r_things.c r_things.h \
+s_sound.c s_sound.h \
+sounds.c sounds.h \
+st_lib.c st_lib.h \
+st_stuff.c st_stuff.h \
+wi_stuff.c wi_stuff.h
+
+FEATURE_DEHACKED_SOURCE_FILES = \
+deh_ammo.c \
+deh_cheat.c \
+deh_strife.c \
+deh_frame.c \
+deh_misc.c deh_misc.h \
+deh_ptr.c \
+deh_sound.c \
+deh_thing.c \
+deh_weapon.c
+
+libstrife_a_SOURCES = $(SOURCE_FILES) \
+ $(FEATURE_DEHACKED_SOURCE_FILES)
+
diff --git a/src/strife/am_map.c b/src/strife/am_map.c
new file mode 100644
index 00000000..e942e3ac
--- /dev/null
+++ b/src/strife/am_map.c
@@ -0,0 +1,1391 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+
+#include "deh_main.h"
+
+#include "z_zone.h"
+#include "doomkeys.h"
+#include "doomdef.h"
+#include "st_stuff.h"
+#include "p_local.h"
+#include "w_wad.h"
+
+#include "m_cheat.h"
+#include "m_controls.h"
+#include "i_system.h"
+
+// Needs access to LFB.
+#include "v_video.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "dstrings.h"
+
+#include "am_map.h"
+
+
+// Automap colors
+#define BACKGROUND 240 // haleyjd [STRIFE]
+#define WALLCOLORS 5 // villsa [STRIFE]
+#define WALLRANGE 16
+#define TSWALLCOLORS 16
+#define FDWALLCOLORS 122 // villsa [STRIFE]
+#define CDWALLCOLORS 116
+#define CTWALLCOLORS 19 // villsa [STRIFE]
+#define SPWALLCOLORS 243 // villsa [STRIFE]
+#define THINGCOLORS 233 // villsa [STRIFE]
+#define MISSILECOLORS 227 // villsa [STRIFE]
+#define SHOOTABLECOLORS 235 // villsa [STRIFE]
+
+// drawing stuff
+
+#define AM_NUMMARKPOINTS 10
+
+// 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)))
+
+// the following is crap
+#define LINE_NEVERSEE ML_DONTDRAW
+
+typedef struct
+{
+ int x, y;
+} fpoint_t;
+
+typedef struct
+{
+ fpoint_t a, b;
+} fline_t;
+
+typedef struct
+{
+ fixed_t x,y;
+} mpoint_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 R ((8*PLAYERRADIUS)/7)
+mline_t cheat_player_arrow[] = {
+ { { -R+R/8, 0 }, { R, 0 } }, // -----
+ { { R, 0 }, { R-R/2, R/6 } }, // ----->
+ { { R, 0 }, { R-R/2, -R/6 } },
+ { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
+ { { -R+R/8, 0 }, { -R-R/8, -R/6 } },
+ { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
+ { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
+ { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
+ { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
+ { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
+ { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
+ { { -R/6, -R/6 }, { 0, -R/6 } },
+ { { 0, -R/6 }, { 0, R/4 } },
+ { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
+ { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
+ { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
+};
+#undef R
+
+#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 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
+
+
+
+
+static int cheating = 0;
+static int grid = 0;
+
+static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
+
+boolean automapactive = false;
+static int finit_width = SCREENWIDTH;
+static int finit_height = SCREENHEIGHT - 32;
+
+// 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 int lightlev; // used for funky strobing effect
+static byte* fb; // pseudo-frame buffer
+static int amclock;
+
+static mpoint_t m_paninc; // how far the window pans each tic (map coords)
+static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords)
+static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords)
+
+static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords)
+static fixed_t m_x2, m_y2; // UR x,y where the window is 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
+
+static patch_t *marknums[10]; // numbers used for marking by the automap
+static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
+static int markpointnum = 0; // next point to be assigned
+static int mapmarknum = 0; // villsa [STRIFE] unused but this was meant to be used for objective based markers
+static int followplayer = 1; // specifies whether to follow the player around
+
+cheatseq_t cheat_amap = CHEAT("topo", 0); // villsa [STRIFE]
+
+static boolean stopped = true;
+
+
+// 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.
+
+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);
+
+}
+
+//
+//
+//
+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;
+}
+
+//
+//
+//
+void AM_saveScaleAndLoc(void)
+{
+ old_m_x = m_x;
+ old_m_y = m_y;
+ old_m_w = m_w;
+ old_m_h = m_h;
+}
+
+//
+//
+//
+void AM_restoreScaleAndLoc(void)
+{
+
+ m_w = old_m_w;
+ m_h = old_m_h;
+ if (!followplayer)
+ {
+ 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);
+}
+
+//
+// adds a marker at the current location
+//
+void AM_addMark(void)
+{
+ markpoints[markpointnum].x = m_x + m_w/2;
+ markpoints[markpointnum].y = m_y + m_h/2;
+ markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
+
+}
+
+//
+// Determines bounding box of all vertices,
+// sets global variables controlling zoom range.
+//
+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);
+
+}
+
+
+//
+//
+//
+void AM_changeWindowLoc(void)
+{
+ if (m_paninc.x || m_paninc.y)
+ {
+ followplayer = 0;
+ 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;
+}
+
+
+//
+//
+//
+void AM_initVariables(void)
+{
+ int pnum;
+ static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 };
+
+ automapactive = true;
+ fb = I_VideoBuffer;
+
+ f_oldloc.x = INT_MAX;
+ amclock = 0;
+ lightlev = 0;
+
+ 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[consoleplayer])
+ {
+ plr = &players[consoleplayer];
+ }
+ else
+ {
+ plr = &players[0];
+
+ for (pnum=0;pnum<MAXPLAYERS;pnum++)
+ {
+ if (playeringame[pnum])
+ {
+ plr = &players[pnum];
+ break;
+ }
+ }
+ }
+
+ 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
+//
+// haleyjd 08/27/10: [STRIFE] Changed marknums to PLMNUM%d
+//
+void AM_loadPics(void)
+{
+ int i;
+ char namebuf[9];
+
+ for (i=0;i<10;i++)
+ {
+ DEH_snprintf(namebuf, 9, "PLMNUM%d", i);
+ marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
+ }
+
+}
+
+void AM_unloadPics(void)
+{
+ int i;
+ char namebuf[9];
+
+ for (i=0;i<10;i++)
+ {
+ DEH_snprintf(namebuf, 9, "PLMNUM%d", i);
+ W_ReleaseLumpName(namebuf);
+ }
+}
+
+void AM_clearMarks(void)
+{
+ int i;
+
+ for (i=0;i<AM_NUMMARKPOINTS;i++)
+ markpoints[i].x = -1; // means empty
+ markpointnum = 0;
+}
+
+//
+// should be called at the start of every level
+// right now, i figure it out myself
+//
+void AM_LevelInit(void)
+{
+ leveljuststarted = 0;
+
+ f_x = f_y = 0;
+ f_w = finit_width;
+ f_h = finit_height;
+
+ AM_clearMarks();
+
+ 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);
+}
+
+
+
+
+//
+//
+//
+void AM_Stop (void)
+{
+ static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED, 0 };
+
+ AM_unloadPics();
+ automapactive = false;
+ ST_Responder(&st_notify);
+ stopped = true;
+}
+
+//
+//
+//
+void AM_Start (void)
+{
+ static int lastlevel = -1;
+ //static int lastepisode = -1;
+
+ if (!stopped) AM_Stop();
+ stopped = false;
+ if (lastlevel != gamemap /*|| lastepisode != gameepisode*/)
+ {
+ AM_LevelInit();
+ lastlevel = gamemap;
+ //lastepisode = gameepisode;
+ }
+ AM_initVariables();
+ AM_loadPics();
+}
+
+//
+// set the window scale to the maximum size
+//
+void AM_minOutWindowScale(void)
+{
+ scale_mtof = min_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+//
+// set the window scale to the minimum size
+//
+void AM_maxOutWindowScale(void)
+{
+ scale_mtof = max_scale_mtof;
+ scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
+ AM_activateNewScale();
+}
+
+
+//
+// Handle events (user inputs) in automap mode
+//
+boolean
+AM_Responder
+( event_t* ev )
+{
+
+ int rc;
+ static int bigstate=0;
+ static char buffer[20];
+ int key;
+
+ rc = false;
+
+ if (!automapactive)
+ {
+ if (ev->type == ev_keydown && ev->data1 == key_map_toggle)
+ {
+ AM_Start ();
+ viewactive = false;
+ rc = true;
+ }
+ }
+ else if (ev->type == ev_keydown)
+ {
+ rc = true;
+ key = ev->data1;
+
+ if (key == key_map_east) // pan right
+ {
+ if (!followplayer) m_paninc.x = FTOM(F_PANINC);
+ else rc = false;
+ }
+ else if (key == key_map_west) // pan left
+ {
+ if (!followplayer) m_paninc.x = -FTOM(F_PANINC);
+ else rc = false;
+ }
+ else if (key == key_map_north) // pan up
+ {
+ if (!followplayer) m_paninc.y = FTOM(F_PANINC);
+ else rc = false;
+ }
+ else if (key == key_map_south) // pan down
+ {
+ if (!followplayer) m_paninc.y = -FTOM(F_PANINC);
+ else rc = false;
+ }
+ else if (key == key_map_zoomout) // zoom out
+ {
+ mtof_zoommul = M_ZOOMOUT;
+ ftom_zoommul = M_ZOOMIN;
+ }
+ else if (key == key_map_zoomin) // zoom in
+ {
+ mtof_zoommul = M_ZOOMIN;
+ ftom_zoommul = M_ZOOMOUT;
+ }
+ else if (key == key_map_toggle)
+ {
+ bigstate = 0;
+ viewactive = true;
+ AM_Stop ();
+ }
+ else if (key == key_map_maxzoom)
+ {
+ bigstate = !bigstate;
+ if (bigstate)
+ {
+ AM_saveScaleAndLoc();
+ AM_minOutWindowScale();
+ }
+ else AM_restoreScaleAndLoc();
+ }
+ else if (key == key_map_follow)
+ {
+ followplayer = !followplayer;
+ f_oldloc.x = INT_MAX;
+ if (followplayer)
+ plr->message = DEH_String(AMSTR_FOLLOWON);
+ else
+ plr->message = DEH_String(AMSTR_FOLLOWOFF);
+ }
+ else if (key == key_map_grid)
+ {
+ grid = !grid;
+ if (grid)
+ plr->message = DEH_String(AMSTR_GRIDON);
+ else
+ plr->message = DEH_String(AMSTR_GRIDOFF);
+ }
+ else if (key == key_map_mark)
+ {
+ sprintf(buffer, "%s %d", DEH_String(AMSTR_MARKEDSPOT), markpointnum);
+ plr->message = buffer;
+ AM_addMark();
+ }
+ else if (key == key_map_clearmark)
+ {
+ AM_clearMarks();
+ plr->message = DEH_String(AMSTR_MARKSCLEARED);
+ }
+ else
+ {
+ rc = false;
+ }
+
+ if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data2))
+ {
+ rc = false;
+ cheating = (cheating+1) % 3;
+ }
+ }
+ else if (ev->type == ev_keyup)
+ {
+ rc = false;
+ key = ev->data1;
+
+ if (key == key_map_east)
+ {
+ if (!followplayer) m_paninc.x = 0;
+ }
+ else if (key == key_map_west)
+ {
+ if (!followplayer) m_paninc.x = 0;
+ }
+ else if (key == key_map_north)
+ {
+ if (!followplayer) m_paninc.y = 0;
+ }
+ else if (key == key_map_south)
+ {
+ if (!followplayer) m_paninc.y = 0;
+ }
+ else if (key == key_map_zoomout || key == key_map_zoomin)
+ {
+ mtof_zoommul = FRACUNIT;
+ ftom_zoommul = FRACUNIT;
+ }
+ }
+
+ return rc;
+
+}
+
+
+//
+// Zooming
+//
+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();
+}
+
+
+//
+//
+//
+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;
+
+ // m_x = FTOM(MTOF(plr->mo->x - m_w/2));
+ // m_y = FTOM(MTOF(plr->mo->y - m_h/2));
+ // m_x = plr->mo->x - m_w/2;
+ // m_y = plr->mo->y - m_h/2;
+
+ }
+
+}
+
+//
+//
+//
+void AM_updateLightLev(void)
+{
+ static int nexttic = 0;
+ //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
+ static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
+ static int litelevelscnt = 0;
+
+ // Change light level
+ if (amclock>nexttic)
+ {
+ lightlev = litelevels[litelevelscnt++];
+ if (litelevelscnt == arrlen(litelevels)) litelevelscnt = 0;
+ nexttic = amclock + 6 - (amclock % 6);
+ }
+
+}
+
+
+//
+// Updates on Game Tick
+//
+void AM_Ticker (void)
+{
+
+ if (!automapactive)
+ return;
+
+ amclock++;
+
+ if (followplayer)
+ 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();
+
+ // Update light level
+ // AM_updateLightLev();
+
+}
+
+
+//
+// Clear automap frame buffer.
+//
+void AM_clearFB(int color)
+{
+ memset(fb, color, f_w*f_h);
+}
+
+
+//
+// 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.
+//
+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;
+ }
+ else
+ {
+ tmp.x = 0;
+ tmp.y = 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
+
+
+//
+// Classic Bresenham w/ whatever optimizations needed for speed
+//
+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;
+
+ 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)
+ {
+ DEH_fprintf(stderr, "fuck %d \r", fuck++);
+ return;
+ }
+
+#define PUTDOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(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;
+ }
+ }
+}
+
+
+//
+// Clip lines, draw visible part sof lines.
+//
+void
+AM_drawMline
+( mline_t* ml,
+ int color )
+{
+ static fline_t fl;
+
+ if (AM_clipMline(ml, &fl))
+ AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
+}
+
+
+
+//
+// Draws flat (floor/ceiling tile) aligned grid lines.
+//
+/*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);
+ }
+
+}*/
+
+//
+// Determines visible lines, draws them.
+// This is LineDef based, not LineSeg based.
+//
+void AM_drawWalls(void)
+{
+ int i;
+ line_t* line;
+ static mline_t l;
+
+ for(i = 0; i < numlines; i++)
+ {
+ line = &lines[i];
+
+ l.a.x = line->v1->x;
+ l.a.y = line->v1->y;
+ l.b.x = line->v2->x;
+ l.b.y = line->v2->y;
+
+ if(cheating || (line->flags & ML_MAPPED))
+ {
+ if((line->flags & LINE_NEVERSEE) && !cheating)
+ continue;
+
+ // villsa [STRIFE]
+ if(line->special == 145 || line->special == 186)
+ {
+ AM_drawMline(&l, SPWALLCOLORS);
+ }
+ // villsa [STRIFE] lightlev is unused here
+ else if(!line->backsector)
+ {
+ AM_drawMline(&l, WALLCOLORS);
+ }
+ else
+ {
+ if(line->special == 39)
+ { // teleporters
+ AM_drawMline(&l, WALLCOLORS+WALLRANGE/2);
+ }
+ else if (line->flags & ML_SECRET) // secret door
+ {
+ // villsa [STRIFE] just draw the wall as is!
+ AM_drawMline(&l, WALLCOLORS);
+ }
+ else if(line->backsector->floorheight != line->frontsector->floorheight)
+ {
+ AM_drawMline(&l, FDWALLCOLORS); // floor level change
+ }
+ else if(line->backsector->ceilingheight != line->frontsector->ceilingheight)
+ {
+ AM_drawMline(&l, CDWALLCOLORS); // ceiling level change
+ }
+ else if (cheating)
+ {
+ AM_drawMline(&l, TSWALLCOLORS);
+ }
+ }
+ }
+ // villsa [STRIFE] show all of the map on map 15
+ else if(plr->powers[pw_allmap] || gamemap == 15)
+ {
+ if(!(line->flags & LINE_NEVERSEE))
+ AM_drawMline(&l, CTWALLCOLORS);
+ }
+ }
+}
+
+
+//
+// Rotation in 2D.
+// Used to rotate player arrow line character.
+//
+void
+AM_rotate
+( fixed_t* x,
+ fixed_t* y,
+ angle_t a )
+{
+ fixed_t tmpx;
+
+ tmpx =
+ FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT])
+ - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
+
+ *y =
+ FixedMul(*x,finesine[a>>ANGLETOFINESHIFT])
+ + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
+
+ *x = tmpx;
+}
+
+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;
+
+ 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);
+
+ 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);
+
+ l.b.x += x;
+ l.b.y += y;
+
+ AM_drawMline(&l, color);
+ }
+}
+
+void AM_drawPlayers(void)
+{
+ int i;
+ player_t* p;
+ // villsa [STRIFE] updated array
+ static int their_colors[] = { 0x80, 0x40, 0xB0, 0x10, 0x30, 0x50, 0xA0, 0x60, 0x90 };
+ int their_color = -1;
+ int color;
+
+ if (!netgame)
+ {
+ // villsa [STRIFE] don't draw cheating player arrow.
+ // Player arrow is yellow instead of white
+ AM_drawLineCharacter
+ (player_arrow, arrlen(player_arrow), 0, plr->mo->angle,
+ 224, plr->mo->x, plr->mo->y);
+ return;
+ }
+
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ their_color++;
+ p = &players[i];
+
+ // villsa [STRIFE] check for gameskill??
+ if((gameskill && deathmatch && !singledemo) && p != plr)
+ continue;
+
+ if(!playeringame[i])
+ continue;
+
+ // villsa [STRIFE] change to 27
+ if(p->powers[pw_invisibility])
+ color = 27; // *close* to black
+ else
+ color = their_colors[their_color];
+
+ AM_drawLineCharacter
+ (player_arrow, arrlen(player_arrow), 0, p->mo->angle,
+ color, p->mo->x, p->mo->y);
+ }
+
+}
+
+//
+// AM_drawThings
+//
+// villsa [STRIFE] no arguments
+//
+void AM_drawThings(void)
+{
+ int i;
+ mobj_t* t;
+ int colors;
+ fixed_t radius;
+
+ // villsa [STRIFE] almost re-written
+ // specific things can have different radius, color and appearence
+ for(i = 0; i < numsectors; i++)
+ {
+ t = sectors[i].thinglist;
+ while(t)
+ {
+ radius = t->radius;
+
+ if(t->flags & (MF_MISSILE|MF_SPECIAL))
+ {
+ colors = MISSILECOLORS;
+ }
+ else if(t->flags & MF_COUNTKILL)
+ {
+ colors = SHOOTABLECOLORS;
+ }
+ else
+ {
+ colors = THINGCOLORS;
+ radius = (16<<FRACBITS);
+ }
+
+ AM_drawLineCharacter (thintriangle_guy, arrlen(thintriangle_guy),
+ radius, t->angle, colors, t->x, t->y);
+
+ t = t->snext;
+ }
+ }
+}
+
+//
+// AM_drawMarks
+//
+void AM_drawMarks(void)
+{
+ int i, fx, fy, w, h;
+
+ for(i = 0; i < AM_NUMMARKPOINTS; i++)
+ {
+ if(markpoints[i].x != -1)
+ {
+ // w = SHORT(marknums[i]->width);
+ // h = SHORT(marknums[i]->height);
+ w = 5; // because something's wrong with the wad, i guess
+ h = 6; // because something's wrong with the wad, i guess
+ fx = CXMTOF(markpoints[i].x);
+ fy = CYMTOF(markpoints[i].y);
+ if(fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
+ {
+ // villsa [STRIFE]
+ if(i >= mapmarknum)
+ V_DrawPatch(fx, fy, marknums[i]);
+ }
+ }
+ }
+
+}
+
+// villsa [STRIFE] unused
+/*void AM_drawCrosshair(int color)
+{
+ fb[(f_w*(f_h+1))/2] = color; // single point for now
+}*/
+
+void AM_Drawer (void)
+{
+ if (!automapactive) return;
+
+ AM_clearFB(BACKGROUND);
+
+ // villsa [STRIFE] not used
+ /*if(grid)
+ AM_drawGrid(GRIDCOLORS);*/
+
+ AM_drawWalls();
+ AM_drawPlayers();
+
+ // villsa [STRIFE] draw things when map powerup is enabled
+ if(cheating == 2 || plr->powers[pw_allmap] > 1)
+ AM_drawThings();
+
+ // villsa [STRIFE] not used
+ //AM_drawCrosshair(XHAIRCOLORS);
+
+ AM_drawMarks();
+ V_MarkRect(f_x, f_y, f_w, f_h);
+
+}
diff --git a/src/strife/am_map.h b/src/strife/am_map.h
new file mode 100644
index 00000000..af390d1b
--- /dev/null
+++ b/src/strife/am_map.h
@@ -0,0 +1,57 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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_cheat.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);
+
+
+extern cheatseq_t cheat_amap;
+
+
+#endif
diff --git a/src/strife/d_englsh.h b/src/strife/d_englsh.h
new file mode 100644
index 00000000..6d615194
--- /dev/null
+++ b/src/strife/d_englsh.h
@@ -0,0 +1,600 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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).
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __D_ENGLSH__
+#define __D_ENGLSH__
+
+//
+// Printed strings for translation
+//
+
+//
+// D_Main.C
+//
+#define D_DEVSTR "Development mode ON.\n"
+#define D_CDROM "CD-ROM Version: Accessing strife.cd\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?"
+// [STRIFE] modified:
+#define LOADNET "you can't load while in a net game!\n\n"PRESSKEY
+#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY
+// [STRIFE] modified:
+#define QSAVESPOT "you haven't picked a\nquicksave slot yet!\n\n"PRESSKEY
+// [STRIFE] modified:
+#define SAVEDEAD "you're not playing a game\n\n"PRESSKEY
+#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN
+// [STRIFE] modified:
+#define QLPROMPT "do you want to quickload\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\nto end the game?\n\n"PRESSYN
+
+// haleyjd 09/11/10: [STRIFE] No "to dos." on this
+#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"
+
+//
+// G_game.C
+//
+#define GGSAVED "game saved."
+
+//
+// HU_stuff.C
+//
+#define HUSTR_MSGU "[Message unsent]"
+
+// haleyjd 08/31/10: [STRIFE] Strife map names
+
+#define HUSTR_1 "AREA 1: sanctuary"
+#define HUSTR_2 "AREA 2: town"
+#define HUSTR_3 "AREA 3: front base"
+#define HUSTR_4 "AREA 4: power station"
+#define HUSTR_5 "AREA 5: prison"
+#define HUSTR_6 "AREA 6: sewers"
+#define HUSTR_7 "AREA 7: castle"
+#define HUSTR_8 "AREA 8: Audience Chamber"
+#define HUSTR_9 "AREA 9: Castle: Programmer's Keep"
+
+#define HUSTR_10 "AREA 10: New Front Base"
+#define HUSTR_11 "AREA 11: Borderlands"
+#define HUSTR_12 "AREA 12: the temple of the oracle"
+#define HUSTR_13 "AREA 13: Catacombs"
+#define HUSTR_14 "AREA 14: mines"
+#define HUSTR_15 "AREA 15: Fortress: Administration"
+#define HUSTR_16 "AREA 16: Fortress: Bishop's Tower"
+#define HUSTR_17 "AREA 17: Fortress: The Bailey"
+#define HUSTR_18 "AREA 18: Fortress: Stores"
+#define HUSTR_19 "AREA 19: Fortress: Security Complex"
+
+#define HUSTR_20 "AREA 20: Factory: Receiving"
+#define HUSTR_21 "AREA 21: Factory: Manufacturing"
+#define HUSTR_22 "AREA 22: Factory: Forge"
+#define HUSTR_23 "AREA 23: Order Commons"
+#define HUSTR_24 "AREA 24: Factory: Conversion Chapel"
+#define HUSTR_25 "AREA 25: Catacombs: Ruined Temple"
+#define HUSTR_26 "AREA 26: proving grounds"
+#define HUSTR_27 "AREA 27: The Lab"
+#define HUSTR_28 "AREA 28: Alien Ship"
+#define HUSTR_29 "AREA 29: Entity"
+
+#define HUSTR_30 "AREA 30: Abandoned Front Base"
+#define HUSTR_31 "AREA 31: Training Facility"
+
+#define HUSTR_32 "AREA 1: Sanctuary"
+#define HUSTR_33 "AREA 2: Town"
+#define HUSTR_34 "AREA 3: Movement Base"
+
+// haleyjd 20110219: [STRIFE] replaced all with Strife chat macros:
+#define HUSTR_CHATMACRO1 "Fucker!"
+#define HUSTR_CHATMACRO2 "--SPLAT-- Instant wall art."
+#define HUSTR_CHATMACRO3 "That had to hurt!"
+#define HUSTR_CHATMACRO4 "Smackings!"
+#define HUSTR_CHATMACRO5 "Gib-O-Matic baby."
+#define HUSTR_CHATMACRO6 "Burn! Yah! Yah!"
+#define HUSTR_CHATMACRO7 "Buh-Bye!"
+#define HUSTR_CHATMACRO8 "Sizzle chest!"
+#define HUSTR_CHATMACRO9 "That sucked!"
+#define HUSTR_CHATMACRO0 "Mommy?"
+
+#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 "Green: "
+#define HUSTR_PLRINDIGO "Indigo: "
+#define HUSTR_PLRBROWN "Brown: "
+#define HUSTR_PLRRED "Red: "
+
+#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"
+
+//
+// ST_stuff.C
+//
+
+#define STSTR_MUS "Music Change"
+#define STSTR_NOMUS "IMPOSSIBLE SELECTION"
+#define STSTR_DQDON "You're Invincible!" // [STRIFE]
+#define STSTR_DQDOFF "You're a looney!" // [STRIFE]
+
+#define STSTR_KFAADDED "Very Happy Ammo Added"
+#define STSTR_FAADDED "Ammo Added" // [STRIFE]
+
+#define STSTR_NCON "No Clipping Mode ON"
+#define STSTR_NCOFF "No Clipping Mode OFF"
+
+#define STSTR_BEHOLD "Bzrk, Inviso, Mask, Health, Pack, Stats" // [STRIFE]
+#define STSTR_BEHOLDX "Power-up Toggled"
+
+#define STSTR_CHOPPERS "... doesn't suck - GM"
+#define STSTR_CLEV "Changing Level..."
+
+//
+// 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"
+
+
+// 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."
+
+
+#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/src/strife/d_items.c b/src/strife/d_items.c
new file mode 100644
index 00000000..66bec442
--- /dev/null
+++ b/src/strife/d_items.c
@@ -0,0 +1,167 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+//
+//-----------------------------------------------------------------------------
+
+
+// We are referring to sprite numbers.
+#include "info.h"
+
+#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
+//
+
+// villsa [STRIFE]
+weaponinfo_t weaponinfo[NUMWEAPONS] =
+{
+ {
+ // fist
+ am_noammo,
+ S_PNCH_03,
+ S_PNCH_02,
+ S_PNCH_01,
+ S_PNCH_04,
+ S_NULL,
+ 1
+ },
+ {
+ // electric bow
+ am_elecbolts,
+ S_XBOW_02,
+ S_XBOW_01,
+ S_XBOW_00,
+ S_XBOW_03,
+ S_NULL,
+ 1
+ },
+ {
+ // rifle
+ am_bullets,
+ S_RIFG_02,
+ S_RIFG_01,
+ S_RIFG_00,
+ S_RIFF_00,
+ S_NULL,
+ 1
+ },
+ {
+ // missile launcher
+ am_missiles,
+ S_MMIS_02,
+ S_MMIS_01,
+ S_MMIS_00,
+ S_MMIS_03,
+ S_NULL,
+ 0
+ },
+ {
+ // grenade launcher
+ am_hegrenades,
+ S_GREN_02,
+ S_GREN_01,
+ S_GREN_00,
+ S_GREN_03,
+ S_GREF_00,
+ 0
+ },
+ {
+ // flame thrower
+ am_cell,
+ S_FLMT_03,
+ S_FLMT_02,
+ S_FLMT_00,
+ S_FLMF_00,
+ S_NULL,
+ 1
+ },
+ {
+ // mauler
+ am_cell,
+ S_BLST_05,
+ S_BLST_04,
+ S_BLST_00,
+ S_BLSF_00,
+ S_NULL,
+ 0
+ },
+ {
+ // sigil
+ am_noammo,
+ S_SIGH_06,
+ S_SIGH_05,
+ S_SIGH_00,
+ S_SIGH_07,
+ S_SIGF_00,
+ 0
+ },
+ {
+ // poison bow
+ am_poisonbolts,
+ S_XBOW_15,
+ S_XBOW_14,
+ S_XBOW_13,
+ S_XBOW_16,
+ S_NULL,
+ 1
+ },
+ {
+ // wp grenade launcher
+ am_wpgrenades,
+ S_GREN_10,
+ S_GREN_09,
+ S_GREN_08,
+ S_GREN_11,
+ S_GREF_03,
+ 0
+ },
+ {
+ // torpedo
+ am_cell,
+ S_BLST_18,
+ S_BLST_17,
+ S_BLST_13,
+ S_BLST_19,
+ S_NULL,
+ 0
+ },
+};
+
+
+
+
+
+
+
+
diff --git a/src/strife/d_items.h b/src/strife/d_items.h
new file mode 100644
index 00000000..91731982
--- /dev/null
+++ b/src/strife/d_items.h
@@ -0,0 +1,50 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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"
+
+
+
+// Weapon info: sprite frames, ammunition use.
+typedef struct
+{
+ ammotype_t ammo;
+ int upstate;
+ int downstate;
+ int readystate;
+ int atkstate;
+ int flashstate;
+ boolean availabledemo; // villsa [STRIFE]
+
+} weaponinfo_t;
+
+extern weaponinfo_t weaponinfo[NUMWEAPONS];
+
+#endif
diff --git a/src/strife/d_main.c b/src/strife/d_main.c
new file mode 100644
index 00000000..ad69f1d4
--- /dev/null
+++ b/src/strife/d_main.c
@@ -0,0 +1,2000 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "deh_main.h"
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "dstrings.h"
+#include "doomfeatures.h"
+#include "sounds.h"
+
+#include "d_iwad.h"
+
+#include "z_zone.h"
+#include "w_main.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_config.h"
+#include "m_controls.h"
+#include "m_misc.h"
+#include "m_menu.h"
+#include "m_saves.h" // haleyjd [STRIFE]
+#include "p_saveg.h"
+#include "p_dialog.h" // haleyjd [STRIFE]
+
+#include "i_endoom.h"
+#include "i_joystick.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "i_swap.h"
+
+#include "g_game.h"
+
+#include "hu_stuff.h"
+#include "wi_stuff.h"
+#include "st_stuff.h"
+#include "am_map.h"
+#include "net_client.h"
+#include "net_dedicated.h"
+#include "net_query.h"
+
+#include "p_setup.h"
+#include "r_local.h"
+
+#include "d_main.h"
+
+// Size of startup splash screen window.
+
+#define INTRO_SCREEN_W 640
+#define INTRO_SCREEN_H 480
+
+//
+// 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
+//
+void D_DoomLoop (void);
+
+static boolean D_AddFile(char *filename);
+
+// Location where savegames are stored
+
+char * savegamedir;
+
+// location of IWAD and WAD files
+
+char * iwadfile;
+
+
+boolean devparm; // started game with -devparm
+boolean nomonsters; // checkparm of -nomonsters
+boolean respawnparm; // checkparm of -respawn
+boolean fastparm; // checkparm of -fast
+boolean flipparm; // [STRIFE] haleyjd 20110629: checkparm of -flip
+
+boolean showintro = true; // [STRIFE] checkparm of -nograph, disables intro
+
+
+//extern int soundVolume;
+//extern int sfxVolume;
+//extern int musicVolume;
+
+extern boolean inhelpscreens;
+
+skill_t startskill;
+int startepisode;
+int startmap;
+boolean autostart;
+int startloadgame;
+
+boolean advancedemo;
+
+// villsa [STRIFE] workparm variable (similar to devparm?)
+boolean workparm = false;
+
+// villsa [STRIFE] stonecold cheat variable
+boolean stonecold = false;
+
+// haleyjd 09/11/10: [STRIFE] Game type variables
+boolean isregistered;
+boolean isdemoversion;
+
+// Store demo, do not accept any inputs
+// haleyjd [STRIFE] Unused.
+//boolean storedemo;
+
+
+char wadfile[1024]; // primary wad file
+char mapdir[1024]; // directory of development maps
+
+int show_endoom = 1;
+int graphical_startup = 1;
+
+// fraggle 06/03/11 [STRIFE]: Unused config variable, preserved
+// for compatibility:
+
+static int comport = 0;
+
+// fraggle 06/03/11 [STRIFE]: Multiplayer nickname?
+
+static char *nickname = NULL;
+
+void D_CheckNetGame (void);
+
+
+//
+// D_ProcessEvents
+// Send all the events of the given timestamp down the responder chain
+//
+void D_ProcessEvents (void)
+{
+ event_t* ev;
+
+ // haleyjd 08/22/2010: [STRIFE] there is no such thing as a "store demo"
+ // version of Strife
+
+ // IF STORE DEMO, DO NOT ACCEPT INPUT
+ //if (storedemo)
+ // return;
+
+ while ((ev = D_PopEvent()) != NULL)
+ {
+ if (M_Responder (ev))
+ continue; // menu ate the event
+ G_Responder (ev);
+ }
+}
+
+
+
+
+//
+// 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
+//
+// haleyjd 08/23/10: [STRIFE]:
+// * Changes to eliminate intermission and change timing of screenwipe
+// * 20100901: Added ST_DrawExternal and popupactivestate static variable
+// * 20110206: Start wipegamestate at GS_UNKNOWN (STRIFE-TODO: rename?)
+//
+gamestate_t wipegamestate = GS_UNKNOWN;
+extern boolean setsizeneeded;
+//extern int showMessages; [STRIFE] no such variable
+void R_ExecuteSetViewSize (void);
+
+void D_Display (void)
+{
+ static boolean viewactivestate = false;
+ static boolean menuactivestate = false;
+ static boolean inhelpscreensstate = false;
+ static boolean popupactivestate = false; // [STRIFE]
+ static boolean fullscreen = false;
+ static gamestate_t oldgamestate = -1;
+ static int borderdrawcount;
+ int nowtime;
+ int tics;
+ int wipestart;
+ int y;
+ boolean done;
+ boolean wipe;
+ boolean redrawsbar;
+
+ if (nodrawers)
+ return; // for comparative timing / profiling
+
+ redrawsbar = false;
+
+ // change the view size if needed
+ if (setsizeneeded)
+ {
+ R_ExecuteSetViewSize ();
+ oldgamestate = -1; // force background redraw
+ borderdrawcount = 3;
+ }
+
+ // save the current screen if about to wipe
+ if (gamestate != wipegamestate)
+ {
+ wipe = true;
+ wipe_StartScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
+ }
+ else
+ wipe = false;
+
+ if (gamestate == GS_LEVEL && gametic)
+ HU_Erase();
+
+ // do buffered drawing
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ if (!gametic)
+ break;
+ if (automapactive)
+ AM_Drawer ();
+ if (wipe || (viewheight != 200 && fullscreen) )
+ redrawsbar = true;
+ // haleyjd 08/29/10: [STRIFE] Always redraw sbar if menu is/was active
+ if (menuactivestate || (inhelpscreensstate && !inhelpscreens))
+ redrawsbar = true; // just put away the help screen
+ ST_Drawer (viewheight == 200, redrawsbar );
+ fullscreen = viewheight == 200;
+ break;
+
+ // haleyjd 08/23/2010: [STRIFE] No intermission
+ /*
+ case GS_INTERMISSION:
+ WI_Drawer ();
+ break;
+ */
+
+ case GS_FINALE:
+ F_Drawer ();
+ break;
+
+ case GS_DEMOSCREEN:
+ D_PageDrawer ();
+ break;
+
+ default:
+ break;
+ }
+
+ // draw buffered stuff to screen
+ I_UpdateNoBlit ();
+
+ // draw the view directly
+ if (gamestate == GS_LEVEL && !automapactive && gametic)
+ R_RenderPlayerView (&players[displayplayer]);
+
+ // clean up border stuff
+ if (gamestate != oldgamestate && gamestate != GS_LEVEL)
+ I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE));
+
+ // see if the border needs to be initially drawn
+ if (gamestate == GS_LEVEL && oldgamestate != GS_LEVEL)
+ {
+ viewactivestate = false; // view was not active
+ R_FillBackScreen (); // draw the pattern into the back screen
+ }
+
+ // see if the border needs to be updated to the screen
+ if (gamestate == GS_LEVEL && !automapactive && scaledviewwidth != 320)
+ {
+ if (menuactive || menuactivestate || !viewactivestate)
+ {
+ borderdrawcount = 3;
+ popupactivestate = false;
+ }
+ if (borderdrawcount)
+ {
+ R_DrawViewBorder (); // erase old menu stuff
+ borderdrawcount--;
+ }
+
+ }
+
+ if (testcontrols)
+ {
+ // Box showing current mouse speed
+
+ V_DrawMouseSpeedBox(testcontrols_mousespeed);
+ }
+
+ menuactivestate = menuactive;
+ viewactivestate = viewactive;
+ inhelpscreensstate = inhelpscreens;
+ oldgamestate = wipegamestate = gamestate;
+
+ // haleyjd 20120208: [STRIFE] Rogue moved this down to below border drawing
+ if (gamestate == GS_LEVEL && gametic)
+ {
+ HU_Drawer ();
+ if(ST_DrawExternal())
+ popupactivestate = true;
+ else if(popupactivestate)
+ {
+ popupactivestate = false;
+ menuactivestate = 1;
+ }
+ }
+
+ // draw pause pic
+ if (paused)
+ {
+ if (automapactive)
+ y = 4;
+ else
+ y = viewwindowy+4;
+ V_DrawPatchDirect(viewwindowx + (scaledviewwidth - 68) / 2, y,
+ W_CacheLumpName (DEH_String("M_PAUSE"), PU_CACHE));
+ }
+
+
+ // menus go directly to the screen
+ M_Drawer (); // menu is drawn even on top of everything
+ NetUpdate (); // send out any new accumulation
+
+
+ // normal update
+ if (!wipe)
+ {
+ I_FinishUpdate (); // page flip or blit buffer
+ return;
+ }
+
+ // wipe update
+ wipe_EndScreen(0, 0, SCREENWIDTH, SCREENHEIGHT);
+
+ wipestart = I_GetTime () - 1;
+
+ do
+ {
+ do
+ {
+ nowtime = I_GetTime ();
+ tics = nowtime - wipestart;
+ I_Sleep(1);
+ } while (tics < 3); // haleyjd 08/23/2010: [STRIFE] Changed from == 0 to < 3
+
+ // haleyjd 08/26/10: [STRIFE] Changed to use ColorXForm wipe.
+ wipestart = nowtime;
+ done = wipe_ScreenWipe(wipe_ColorXForm
+ , 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);
+}
+
+//
+// Add configuration file variable bindings.
+//
+
+void D_BindVariables(void)
+{
+ int i;
+
+ M_ApplyPlatformDefaults();
+
+ I_BindVideoVariables();
+ I_BindJoystickVariables();
+ I_BindSoundVariables();
+
+ M_BindBaseControls();
+ M_BindWeaponControls();
+ M_BindMapControls();
+ M_BindMenuControls();
+ M_BindStrifeControls(); // haleyjd 09/01/10: [STRIFE]
+ M_BindChatControls(MAXPLAYERS);
+
+ key_multi_msgplayer[0] = HUSTR_KEYGREEN;
+ key_multi_msgplayer[1] = HUSTR_KEYINDIGO;
+ key_multi_msgplayer[2] = HUSTR_KEYBROWN;
+ key_multi_msgplayer[3] = HUSTR_KEYRED;
+
+#ifdef FEATURE_MULTIPLAYER
+ NET_BindVariables();
+#endif
+
+ // haleyjd 08/29/10: [STRIFE]
+ // * Added voice volume
+ // * Added back flat
+ // * Removed show_messages
+ // * Added show_talk
+ // fraggle 03/06/10: [STRIFE]
+ // * Removed detailLevel
+ // * screenblocks -> screensize
+ // * Added nickname, comport
+
+ M_BindVariable("mouse_sensitivity", &mouseSensitivity);
+ M_BindVariable("sfx_volume", &sfxVolume);
+ M_BindVariable("music_volume", &musicVolume);
+ M_BindVariable("voice_volume", &voiceVolume);
+ M_BindVariable("show_talk", &dialogshowtext);
+ M_BindVariable("screensize", &screenblocks);
+ M_BindVariable("snd_channels", &snd_channels);
+ M_BindVariable("vanilla_savegame_limit", &vanilla_savegame_limit);
+ M_BindVariable("vanilla_demo_limit", &vanilla_demo_limit);
+ M_BindVariable("show_endoom", &show_endoom);
+ M_BindVariable("back_flat", &back_flat);
+ M_BindVariable("graphical_startup", &graphical_startup);
+
+ M_BindVariable("nickname", &nickname);
+ M_BindVariable("comport", &comport);
+
+ // Multiplayer chat macros
+
+ for (i=0; i<10; ++i)
+ {
+ char buf[12];
+
+ sprintf(buf, "chatmacro%i", i);
+ M_BindVariable(buf, &chat_macros[i]);
+ }
+}
+
+//
+// D_GrabMouseCallback
+//
+// Called to determine whether to grab the mouse pointer
+//
+
+boolean D_GrabMouseCallback(void)
+{
+ // Drone players don't need mouse focus
+
+ if (drone)
+ return false;
+
+ // when menu is active or game is paused, release the mouse
+
+ if (menuactive || paused)
+ return false;
+
+ // only grab mouse when playing levels (but not demos)
+
+ return (gamestate == GS_LEVEL) && !demoplayback;
+}
+
+//
+// D_DoomLoop
+//
+// haleyjd 08/23/10: [STRIFE] Verified unmodified.
+//
+void D_DoomLoop (void)
+{
+ if (demorecording)
+ G_BeginRecording ();
+
+ TryRunTics();
+
+ I_SetWindowTitle(gamedescription);
+ I_InitGraphics();
+
+ I_EnableLoadingDisk();
+ I_SetGrabMouseCallback(D_GrabMouseCallback);
+
+ V_RestoreBuffer();
+ R_ExecuteSetViewSize();
+
+ D_StartGameLoop();
+
+ if (testcontrols)
+ {
+ wipegamestate = gamestate;
+ }
+
+ while (1)
+ {
+ // frame syncronous IO operations
+ I_StartFrame ();
+
+ // process one or more tics
+ TryRunTics (); // will run at least one tic
+
+ S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
+
+ // Update display, next frame, with current state.
+ if (screenvisible)
+ D_Display ();
+ }
+}
+
+
+
+//
+// DEMO LOOP
+//
+int demosequence;
+int pagetic;
+char *pagename;
+
+
+//
+// D_PageTicker
+// Handles timing for warped projection
+//
+// haleyjd 08/22/2010: [STRIFE] verified unmodified
+//
+void D_PageTicker (void)
+{
+ if (--pagetic < 0)
+ D_AdvanceDemo ();
+}
+
+
+
+//
+// D_PageDrawer
+//
+// haleyjd 08/22/2010: [STRIFE] verified unmodified
+//
+void D_PageDrawer (void)
+{
+ V_DrawPatch (0, 0, W_CacheLumpName(pagename, PU_CACHE));
+}
+
+
+//
+// D_AdvanceDemo
+// Called after each demo or intro demosequence finishes
+//
+// haleyjd 08/22/2010: [STRIFE] verified unmodified
+//
+void D_AdvanceDemo (void)
+{
+ advancedemo = true;
+}
+
+
+//
+// This cycles through the demo sequences.
+// FIXME - version dependend demo numbers?
+//
+// [STRIFE] Modified for the opening slideshow and the exit screen
+//
+void D_DoAdvanceDemo (void)
+{
+ players[consoleplayer].playerstate = PST_LIVE; // not reborn
+ advancedemo = false;
+ usergame = false; // no save / end game here
+ paused = false;
+ gameaction = ga_nothing;
+
+ // villsa 09/12/10: [STRIFE] converted pagetics to ticrate
+ switch (demosequence)
+ {
+ case -5: // exit the game
+ I_Quit();
+ return;
+ case -4: // show exit screen
+ menuactive = false;
+ pagetic = 3*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("PANEL7");
+ S_StartMusic(mus_fast);
+ if(isdemoversion)
+ demosequence = -3; // show Velocity logo
+ else
+ demosequence = -5; // exit
+ return;
+ case -3: // show Velocity logo for demo version
+ pagetic = 6*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("vellogo");
+ demosequence = -5; // exit
+ return;
+ case -2: // title screen
+ pagetic = 6*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("TITLEPIC");
+ S_StartMusic(mus_logo);
+ demosequence = -1; // start intro cinematic
+ return;
+ case -1: // start of intro cinematic
+ pagetic = 10;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("PANEL0");
+ S_StartSound(NULL, sfx_rb2act);
+ wipegamestate = -1;
+ break;
+ case 0: // Rogue logo
+ pagetic = 4*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("RGELOGO");
+ wipegamestate = -1;
+ break;
+ case 1:
+ pagetic = 7*TICRATE; // The comet struck our planet without
+ gamestate = GS_DEMOSCREEN; // warning.We lost our paradise in a
+ pagename = DEH_String("PANEL1"); // single, violent stroke.
+ I_StartVoice(DEH_String("pro1"));
+ S_StartMusic(mus_intro);
+ break;
+ case 2:
+ pagetic = 9*TICRATE; // The impact released a virus which
+ gamestate = GS_DEMOSCREEN; // swept through the land and killed
+ pagename = DEH_String("PANEL2"); // millions. They turned out to be
+ I_StartVoice(DEH_String("pro2")); // the lucky ones...
+ break;
+ case 3:
+ pagetic = 12*TICRATE; // For those that did not die became
+ gamestate = GS_DEMOSCREEN; // mutations of humanity. Some became
+ pagename = DEH_String("PANEL3"); // fanatics who heard the voice of a
+ I_StartVoice(DEH_String("pro3")); // malignant God in their heads, and
+ break; // called themselves the Order.
+ case 4:
+ pagetic = 11*TICRATE; // Those of us who were deaf to this
+ pagename = DEH_String("PANEL4"); // voice suffer horribly and are
+ gamestate = GS_DEMOSCREEN; // forced to serve these ruthless
+ I_StartVoice(DEH_String("pro4")); // psychotics, who wield weapons more
+ break; // powerful than anything we can muster.
+ case 5:
+ pagetic = 10*TICRATE; // They destroy our women and children,
+ gamestate = GS_DEMOSCREEN; // so that we must hide them underground,
+ pagename = DEH_String("PANEL5"); // and live like animals in constant
+ I_StartVoice(DEH_String("pro5")); // fear for our lives.
+ break;
+ case 6: // But there are whispers of discontent.
+ pagetic = 16*TICRATE; // If we organize, can we defeat our
+ gamestate = GS_DEMOSCREEN; // masters? Weapons are being stolen,
+ pagename = DEH_String("PANEL6"); // soldiers are being trained. A
+ I_StartVoice(DEH_String("pro6")); // Movement is born! Born of lifelong
+ break; // STRIFE!
+ case 7: // titlepic again - unused...
+ pagetic = 9*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("TITLEPIC");
+ wipegamestate = -1;
+ break;
+ case 8: // demo
+ ClearTmp();
+ pagetic = 9*TICRATE;
+ G_DeferedPlayDemo(DEH_String("demo1"));
+ break;
+ case 9: // velocity logo? - unused...
+ pagetic = 6*TICRATE;
+ gamestate = GS_DEMOSCREEN;
+ pagename = DEH_String("vellogo");
+ wipegamestate = -1;
+ break;
+ case 10: // credits
+ gamestate = GS_DEMOSCREEN;
+ pagetic = 12*TICRATE;
+ pagename = DEH_String("CREDIT");
+ wipegamestate = -1;
+ break;
+ default:
+ break;
+ }
+
+ ++demosequence;
+
+ if(demosequence > 11)
+ demosequence = -2;
+ if(demosequence == 7 || demosequence == 9)
+ ++demosequence;
+}
+
+
+
+//
+// D_StartTitle
+//
+// [STRIFE]
+// haleyjd 09/11/10: Small modifications for new demo sequence.
+//
+void D_StartTitle (void)
+{
+ gamestate = GS_DEMOSCREEN;
+ gameaction = ga_nothing;
+ demosequence = -2;
+ D_AdvanceDemo ();
+}
+
+//
+// D_QuitGame
+//
+// [STRIFE] New function
+// haleyjd 09/11/10: Sets up the quit game snippet powered by the
+// demo sequence.
+//
+void D_QuitGame(void)
+{
+ gameaction = ga_nothing;
+ demosequence = -4;
+ D_AdvanceDemo();
+}
+
+// Strings for dehacked replacements of the startup banner
+//
+// These are from the original source: some of them are perhaps
+// not used in any dehacked patches
+
+static char *banners[] =
+{
+ // strife1.wad:
+
+ " "
+ "STRIFE: Quest for the Sigil v1.2"
+ " "
+};
+
+//
+// Get game name: if the startup banner has been replaced, use that.
+// Otherwise, use the name given
+//
+
+static char *GetGameName(char *gamename)
+{
+ size_t i;
+ char *deh_sub;
+
+ for (i=0; i<arrlen(banners); ++i)
+ {
+ // Has the banner been replaced?
+
+ deh_sub = DEH_String(banners[i]);
+
+ if (deh_sub != banners[i])
+ {
+ // Has been replaced
+ // We need to expand via printf to include the Doom version
+ // number
+ // We also need to cut off spaces to get the basic name
+
+ gamename = Z_Malloc(strlen(deh_sub) + 10, PU_STATIC, 0);
+ sprintf(gamename, deh_sub, STRIFE_VERSION / 100, STRIFE_VERSION % 100);
+
+ while (gamename[0] != '\0' && isspace(gamename[0]))
+ strcpy(gamename, gamename+1);
+
+ while (gamename[0] != '\0' && isspace(gamename[strlen(gamename)-1]))
+ gamename[strlen(gamename) - 1] = '\0';
+
+ return gamename;
+ }
+ }
+
+ return gamename;
+}
+
+//
+// Find out what version of Doom is playing.
+//
+
+void D_IdentifyVersion(void)
+{
+ // gamemission is set up by the D_FindIWAD function. But if
+ // we specify '-iwad', we have to identify using
+ // IdentifyIWADByName. However, if the iwad does not match
+ // any known IWAD name, we may have a dilemma. Try to
+ // identify by its contents.
+
+ // STRIFE-TODO: some elaborate checks? for now we assume...
+ // The logic in strife1.exe is simple:
+ // * if strife1.wad is found, set isregistered = true
+ // * if strife0.wad is found, set isdemoversion = true
+
+ // Make sure gamemode is set up correctly
+ gamemode = commercial;
+ gamemission = strife;
+ isregistered = true;
+
+ // Load voices.wad
+ if(isregistered)
+ {
+ char *name = D_FindWADByName("voices.wad");
+
+ if(!name) // not found?
+ {
+ int p;
+
+ // haleyjd STRIFE-FIXME: Temporary?
+ // If -iwad was used, check and see if voices.wad exists on the
+ // same filepath.
+ if((p = M_CheckParm("-iwad")) && p < myargc - 1)
+ {
+ char *iwad = myargv[p + 1];
+ size_t len = strlen(iwad) + 24;
+ char *filename = malloc(len);
+ char sepchar;
+
+ // how the heck is Choco surviving without this routine?
+ sepchar = M_GetFilePath(iwad, filename, len);
+ filename[strlen(filename)] = sepchar;
+ strcat(filename, "voices.wad");
+
+ if(!M_FileExists(filename))
+ disable_voices = 1;
+ else
+ name = filename; // STRIFE-FIXME: memory leak!!
+ }
+ else
+ disable_voices = 1;
+ }
+
+ if(disable_voices) // voices disabled?
+ {
+ if(devparm)
+ printf("Voices disabled\n");
+ return;
+ }
+
+ D_AddFile(name);
+ }
+}
+
+#if 0
+//
+// DoTimeBomb
+//
+// haleyjd 08/23/2010: [STRIFE] New function
+// Code with no xrefs; probably left over from a private alpha or beta.
+// Translated here because it explains what the SERIAL lump was meant to do.
+//
+void DoTimeBomb(void)
+{
+ dosdate_t date;
+ char *serial;
+ int serialnum;
+ int serial_year;
+ int serial_month;
+
+ serial = W_CacheLumpName("serial", PU_CACHE);
+ serialnum = atoi(serial);
+
+ // Rogue, much like Governor Mourel, were lousy liars. These deceptive
+ // error messages are pretty low :P
+ dos_getdate(&date);
+ if(date.year > 1996 || date.day > 15 && date.month > 4)
+ I_Error("Data error! Corrupted WAD File!");
+ serial_year = serialnum / 10000;
+ serial_month = serialnum / 100 - 100 * serial_year;
+ if(date.year < serial_year ||
+ date.day < serialnum - 100 * serial_month - 10000 * serial_year &&
+ date.month < serial_month)
+ I_Error("Bad wadfile");
+}
+#endif
+
+// Set the gamedescription string
+
+void D_SetGameDescription(void)
+{
+ gamedescription = GetGameName("Strife: Quest for the Sigil");
+}
+
+// print title for every printed line
+char title[128];
+
+static boolean D_AddFile(char *filename)
+{
+ wad_file_t *handle;
+
+ printf(" adding %s\n", filename);
+ handle = W_AddFile(filename);
+
+ return handle != NULL;
+}
+
+// Copyright message banners
+// Some dehacked mods replace these. These are only displayed if they are
+// replaced by dehacked.
+// haleyjd 08/22/2010: [STRIFE] altered to match strings from binary
+static char *copyright_banners[] =
+{
+ "===========================================================================\n"
+ "ATTENTION: This version of STRIFE has extra files added to it.\n"
+ " You will not receive technical support for modified games.\n"
+ "===========================================================================\n",
+
+ "===========================================================================\n"
+ " This version is NOT SHAREWARE, do not distribute!\n"
+ " Please report software piracy to the SPA: 1-800-388-PIR8\n"
+ "===========================================================================\n",
+
+ "===========================================================================\n"
+ " Shareware!\n"
+ "===========================================================================\n"
+};
+
+// Prints a message only if it has been modified by dehacked.
+
+void PrintDehackedBanners(void)
+{
+ size_t i;
+
+ for (i=0; i<arrlen(copyright_banners); ++i)
+ {
+ char *deh_s;
+
+ deh_s = DEH_String(copyright_banners[i]);
+
+ if (deh_s != copyright_banners[i])
+ {
+ printf("%s", deh_s);
+
+ // Make sure the modified banner always ends in a newline character.
+ // If it doesn't, add a newline. This fixes av.wad.
+
+ if (deh_s[strlen(deh_s) - 1] != '\n')
+ {
+ printf("\n");
+ }
+ }
+ }
+}
+
+static struct
+{
+ char *description;
+ char *cmdline;
+ GameVersion_t version;
+} gameversions[] = {
+ { "Strife 1.2", "1.2", exe_strife_1_2 },
+ { "Strife 1.31", "1.31", exe_strife_1_31 },
+ { NULL, NULL, 0 }
+};
+
+// Initialize the game version
+
+static void InitGameVersion(void)
+{
+ int p;
+ int i;
+
+ // haleyjd: we support emulating either the 1.2 or the 1.31 versions of
+ // Strife, which are the most significant. 1.2 is the most mature version
+ // that still has the single saveslot restriction, whereas 1.31 is the
+ // final revision. The differences between the two are barely worth
+ // mentioning aside from that main one.
+
+ //!
+ // @arg <version>
+ // @category compat
+ //
+ // Emulate a specific version of Doom. Valid values are "1.2" and "1.31".
+ //
+
+ p = M_CheckParmWithArgs("-gameversion", 1);
+
+ if (p)
+ {
+ for (i=0; gameversions[i].description != NULL; ++i)
+ {
+ if (!strcmp(myargv[p+1], gameversions[i].cmdline))
+ {
+ gameversion = gameversions[i].version;
+ break;
+ }
+ }
+
+ if (gameversions[i].description == NULL)
+ {
+ printf("Supported game versions:\n");
+
+ for (i=0; gameversions[i].description != NULL; ++i)
+ {
+ printf("\t%s (%s)\n", gameversions[i].cmdline,
+ gameversions[i].description);
+ }
+
+ I_Error("Unknown game version '%s'", myargv[p+1]);
+ }
+ }
+ else
+ {
+ gameversion = exe_strife_1_31;
+ }
+}
+
+void PrintGameVersion(void)
+{
+ int i;
+
+ for (i=0; gameversions[i].description != NULL; ++i)
+ {
+ if (gameversions[i].version == gameversion)
+ {
+ printf("Emulating the behavior of the "
+ "'%s' executable.\n", gameversions[i].description);
+ break;
+ }
+ }
+}
+
+// Function called at exit to display the ENDOOM screen
+
+static void D_Endoom(void)
+{
+ byte *endoom;
+
+ // Don't show ENDOOM if we have it disabled, or we're running
+ // in screensaver or control test mode.
+
+ if (!show_endoom || screensaver_mode || testcontrols)
+ {
+ return;
+ }
+
+ // haleyjd 08/27/10: [STRIFE] ENDOOM -> ENDSTRF
+ endoom = W_CacheLumpName(DEH_String("ENDSTRF"), PU_STATIC);
+
+ I_Endoom(endoom);
+}
+
+//=============================================================================
+//
+// haleyjd: Chocolate Strife Specifics
+//
+// None of the code in here is from the original executable, but is needed for
+// other reasons.
+
+//
+// D_PatchClipCallback
+//
+// haleyjd 08/28/10: Clip patches to the framebuffer without errors.
+// Returns false if V_DrawPatch should return without drawing.
+//
+boolean D_PatchClipCallback(patch_t *patch, int x, int y)
+{
+ // note that offsets were already accounted for in V_DrawPatch
+ return (x >= 0 && y >= 0
+ && x + SHORT(patch->width) <= SCREENWIDTH
+ && y + SHORT(patch->height) <= SCREENHEIGHT);
+}
+
+//
+// D_InitChocoStrife
+//
+// haleyjd 08/28/10: Take care of some Strife-specific initialization
+// that is necessitated by Chocolate Doom issues, such as setting global
+// callbacks.
+//
+static void D_InitChocoStrife(void)
+{
+ // set the V_DrawPatch clipping callback
+ V_SetPatchClipCallback(D_PatchClipCallback);
+}
+
+
+//
+// STRIFE Graphical Intro Sequence
+//
+
+#define MAXINTROPROGRESS 69
+
+static int introprogress; // track the progress of the intro
+
+static byte *rawgfx_startup0; // raw linear gfx for intro
+static byte *rawgfx_startp[4];
+static byte *rawgfx_startlz[2];
+static byte *rawgfx_startbot;
+
+//
+// D_IntroBackground
+//
+// [STRIFE] New function
+// haleyjd 20110206: Strife only drew this once, but for supporting double-
+// buffered or page-flipped surfaces it is best to redraw the entire screen
+// every frame.
+//
+static void D_IntroBackground(void)
+{
+ patch_t *panel0;
+
+ if(!showintro)
+ return;
+
+ // Slam up PANEL0 to fill the background entirely (wasn't needed in vanilla)
+ panel0 = W_CacheLumpName("PANEL0", PU_CACHE);
+ V_DrawPatch(0, 0, panel0);
+
+ // Strife cleared the screen somewhere in the low-level code between the
+ // intro and the titlescreen, so this is to take care of that and get
+ // proper fade-in behavior on the titlescreen
+ if(introprogress >= MAXINTROPROGRESS)
+ {
+ I_FinishUpdate();
+ return;
+ }
+
+ // Draw a 95-pixel rect from STARTUP0 starting at y=57 to (0,41) on the
+ // screen (this was a memcpy directly to 0xA3340 in low DOS memory)
+ V_DrawBlock(0, 41, 320, 95, rawgfx_startup0 + (320*57));
+}
+
+//
+// D_InitIntroSequence
+//
+// [STRIFE] New function
+// haleyjd 20110206: Initialize the graphical introduction sequence
+//
+
+static int saved_screen_width, saved_screen_height;
+static int saved_fullscreen, saved_aspect_ratio_correct;
+
+static void D_InitIntroSequence(void)
+{
+ if(showintro)
+ {
+ // Intro splash screen runs in a window. We must save the actual
+ // display settings, and temporarily overwrite them with the
+ // windowed-mode settings. The real settings will be restored
+ // when the intro screen finishes.
+
+ // INTRO-FIXME:
+ // This is causing problems on Windows, including interruption of the
+ // sound playing. I would like to see this changed back to how it worked
+ // before once the netcode can function along with it.
+ // -haleyjd
+
+ saved_screen_width = screen_width;
+ saved_screen_height = screen_height;
+ saved_aspect_ratio_correct = aspect_ratio_correct;
+ saved_fullscreen = fullscreen;
+
+ // If the game display settings are to run in a small window, it
+ // makes no sense to switch to a larger window for the splash
+ // screen, so use the configured settings.
+
+ // INTRO-FIXME: how does this make sense?
+ // If I have an 800x600 game window (in windowed mode), then I expect an
+ // 800x600 intro too,
+ // and indeed the code below is capable of drawing at any resolution.
+ // Either the logic is off or I simply totally disagree with the original
+ // motivation that lead to limiting it to 640x480.
+ // -haleyjd
+
+ if (fullscreen
+ || screen_width > INTRO_SCREEN_W || screen_height > INTRO_SCREEN_H)
+ {
+ screen_width = INTRO_SCREEN_W;
+ screen_height = INTRO_SCREEN_H;
+ aspect_ratio_correct = 1;
+ }
+
+ fullscreen = 0;
+
+ // In vanilla Strife, Mode 13h was initialized directly in D_DoomMain.
+ // We have to be a little more courteous of the low-level code here.
+ I_SetWindowTitle(gamedescription);
+ I_InitGraphics();
+ V_RestoreBuffer(); // make the V_ routines work
+
+ // Load all graphics
+ rawgfx_startup0 = W_CacheLumpName("STARTUP0", PU_STATIC);
+ rawgfx_startp[0] = W_CacheLumpName("STRTPA1", PU_STATIC);
+ rawgfx_startp[1] = W_CacheLumpName("STRTPB1", PU_STATIC);
+ rawgfx_startp[2] = W_CacheLumpName("STRTPC1", PU_STATIC);
+ rawgfx_startp[3] = W_CacheLumpName("STRTPD1", PU_STATIC);
+ rawgfx_startlz[0] = W_CacheLumpName("STRTLZ1", PU_STATIC);
+ rawgfx_startlz[1] = W_CacheLumpName("STRTLZ2", PU_STATIC);
+ rawgfx_startbot = W_CacheLumpName("STRTBOT", PU_STATIC);
+
+ // Draw the background
+ D_IntroBackground();
+ }
+ /*
+ // STRIFE-FIXME: This was actually displayed on a special textmode
+ // screen with ANSI color codes... would require use of textlib to
+ // emulate properly...
+ else
+ {
+ puts(DEH_String("Conversation ON"));
+ puts(DEH_String("Rogue Entertainment"));
+ puts(DEH_String("and"));
+ puts(DEH_String("Velocity Games"));
+ puts(DEH_String("present"));
+ puts(DEH_String("S T R I F E"));
+ puts(DEH_String("Loading..."));
+ }
+ */
+}
+
+// End of intro splash screen.
+
+static void D_FinishIntroSequence(void)
+{
+ if (showintro)
+ {
+ I_ShutdownGraphics();
+
+ // Restore display settings to the actual ones.
+
+ screen_width = saved_screen_width;
+ screen_height = saved_screen_height;
+ fullscreen = saved_fullscreen;
+ aspect_ratio_correct = saved_aspect_ratio_correct;
+ }
+}
+
+//
+// D_DrawIntroSequence
+//
+// [STRIFE] New function
+// haleyjd 20110206: Refresh the intro sequence
+//
+static void D_DrawIntroSequence(void)
+{
+ int laserpos;
+ int robotpos;
+
+ if(!showintro)
+ return;
+
+ D_IntroBackground(); // haleyjd: refresh the background
+
+ // Laser position
+ laserpos = (200 * introprogress / MAXINTROPROGRESS) + 60;
+
+ // BUG: (?) Due to this clip, the laser never even comes close to
+ // touching the peasant; confirmed with vanilla. This MAY have been
+ // intentional, for effect, however, since no death frames are shown
+ // either... kind of a black-out death.
+ if(laserpos > 200)
+ laserpos = 200;
+
+ // Draw the laser
+ // Blitted 16 bytes for 16 rows starting at 705280 + laserpos
+ // (705280 - 0xA0000) / 320 == 156
+ V_DrawBlock(laserpos, 156, 16, 16, rawgfx_startlz[laserpos % 2]);
+
+ // Robot position
+ robotpos = laserpos % 5 - 2;
+
+ // Draw the robot
+ // Blitted 48 bytes for 48 rows starting at 699534 + (320*robotpos)
+ // 699534 - 0xA0000 == 44174, which % 320 == 14, / 320 == 138
+ V_DrawBlock(14, 138 + robotpos, 48, 48, rawgfx_startbot);
+
+ // Draw the peasant
+ // Blitted 32 bytes for 64 rows starting at 699142
+ // 699142 - 0xA0000 == 43782, which % 320 == 262, / 320 == 136
+ V_DrawBlock(262, 136, 32, 64, rawgfx_startp[laserpos % 4]);
+
+ I_FinishUpdate();
+}
+
+//
+// D_IntroTick
+//
+// Advance the intro sequence
+//
+void D_IntroTick(void)
+{
+ static boolean didsound = false; // haleyjd 20120209
+
+ if(devparm)
+ return;
+
+ ++introprogress;
+ if(introprogress >= MAXINTROPROGRESS)
+ {
+ D_IntroBackground(); // haleyjd: clear the bg anyway
+
+ // haleyjd 20120209: This isn't 100% true to vanilla because vanilla
+ // would play this sound a half-dozen times. BUT, in vanilla, for
+ // whatever reason, under DMX, playing the same sound multiple times
+ // doesn't add up violently like it does under SDL_mixer. This means
+ // that without this one-time limitation, the sound is far too loud.
+ if(!didsound)
+ {
+ S_StartSound(NULL, sfx_psdtha);
+ didsound = true;
+ }
+ }
+ else
+ D_DrawIntroSequence();
+}
+
+//
+// End Chocolate Strife Specifics
+//
+//=============================================================================
+
+//
+// D_DoomMain
+//
+void D_DoomMain (void)
+{
+ int p;
+ char file[256];
+ char demolumpname[9];
+
+ I_AtExit(D_Endoom, false);
+
+ // haleyjd 20110206 [STRIFE]: -nograph parameter
+
+ //!
+ // @vanilla
+ //
+ // Disable graphical introduction sequence
+ //
+
+ if (M_ParmExists("-nograph"))
+ showintro = false;
+
+ // Undocumented:
+ // Invoked by setup to test the controls.
+
+ if (M_ParmExists("-testcontrols"))
+ {
+ testcontrols = true;
+ showintro = false;
+ }
+
+ // haleyjd 20110206: Moved up -devparm for max visibility
+
+ //!
+ // @vanilla
+ //
+ // Developer mode. F1 saves a screenshot in the current working
+ // directory.
+ //
+
+ devparm = M_CheckParm ("-devparm");
+
+ // print banner
+
+ I_PrintBanner(PACKAGE_STRING);
+
+ //DEH_printf("Z_Init: Init zone memory allocation daemon. \n"); [STRIFE] removed
+ Z_Init ();
+
+#ifdef FEATURE_MULTIPLAYER
+ //!
+ // @category net
+ //
+ // Start a dedicated server, routing packets but not participating
+ // in the game itself.
+ //
+
+ if (M_CheckParm("-dedicated") > 0)
+ {
+ printf("Dedicated server mode.\n");
+ NET_DedicatedServer();
+
+ // Never returns
+ }
+
+ //!
+ // @category net
+ //
+ // Query the Internet master server for a global list of active
+ // servers.
+ //
+
+ if (M_CheckParm("-search"))
+ {
+ NET_MasterQuery();
+ exit(0);
+ }
+
+ //!
+ // @arg <address>
+ // @category net
+ //
+ // Query the status of the server running on the given IP
+ // address.
+ //
+
+ p = M_CheckParmWithArgs("-query", 1);
+
+ if (p)
+ {
+ NET_QueryAddress(myargv[p+1]);
+ exit(0);
+ }
+
+ //!
+ // @category net
+ //
+ // Search the local LAN for running servers.
+ //
+
+ if (M_CheckParm("-localsearch"))
+ {
+ NET_LANQuery();
+ exit(0);
+ }
+
+#endif
+
+#ifdef FEATURE_DEHACKED
+ if(devparm)
+ printf("DEH_Init: Init Dehacked support.\n");
+ DEH_Init();
+#endif
+
+ iwadfile = D_FindIWAD(IWAD_MASK_STRIFE, &gamemission);
+
+ // None found?
+
+ if (iwadfile == NULL)
+ {
+ I_Error("Game mode indeterminate. No IWAD file was found. Try\n"
+ "specifying one with the '-iwad' command line parameter.\n");
+ }
+
+ modifiedgame = false;
+
+ //!
+ // @vanilla
+ //
+ // Disable monsters.
+ //
+
+ nomonsters = M_CheckParm ("-nomonsters");
+
+ //!
+ // Sets Rogue playtesting mode (godmode, noclip toggled by backspace)
+ //
+
+ workparm = M_CheckParm ("-work");
+
+ //!
+ // Attemps to flip player gun sprites, but is broken.
+ //
+
+ flipparm = M_CheckParm ("-flip");
+
+ //!
+ // @vanilla
+ //
+ // Monsters respawn after being killed.
+ //
+
+ respawnparm = M_CheckParm ("-respawn");
+
+ //!
+ // @vanilla
+ //
+ // Monsters move faster.
+ //
+
+ fastparm = M_CheckParm ("-fast");
+
+ I_DisplayFPSDots(devparm);
+
+ // haleyjd 20110206 [STRIFE]: -devparm implies -nograph
+ if(devparm)
+ showintro = false;
+
+ // Note: Vanilla Strife does not understand the -deathmatch command
+ // line parameter. deathmatch=1 is the default behavior when
+ // playing a netgame.
+
+ //!
+ // @category net
+ // @vanilla
+ //
+ // Start a deathmatch game. Weapons do not stay in place and
+ // all items respawn after 30 seconds.
+ //
+
+ if (M_CheckParm ("-altdeath"))
+ deathmatch = 2;
+
+ if (devparm)
+ DEH_printf(D_DEVSTR);
+
+ // find which dir to use for config files
+
+#ifdef _WIN32
+
+ //!
+ // @platform windows
+ // @vanilla
+ //
+ // Save configuration data and savegames in c:\doomdata,
+ // allowing play from CD.
+ //
+
+ if (M_CheckParm("-cdrom") > 0)
+ {
+ printf(D_CDROM);
+
+ // haleyjd 08/22/2010: [STRIFE] Use strife.cd folder for -cdrom
+ M_SetConfigDir("c:\\strife.cd\\");
+ }
+ else
+#endif
+ {
+ // Auto-detect the configuration dir.
+
+ M_SetConfigDir(NULL);
+ }
+
+ //!
+ // @arg <x>
+ // @vanilla
+ //
+ // Turbo mode. The player's speed is multiplied by x%. If unspecified,
+ // x defaults to 200. Values are rounded up to 10 and down to 400.
+ //
+
+ 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;
+ DEH_printf("turbo scale: %i%%\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;
+ }
+
+ // init subsystems
+ // DEH_printf("V_Init: allocate screens.\n"); [STRIFE] removed
+ V_Init ();
+
+ // Load configuration files before initialising other subsystems.
+ // haleyjd 08/22/2010: [STRIFE] - use strife.cfg
+ // DEH_printf("M_LoadDefaults: Load system defaults.\n"); [STRIFE] removed
+ M_SetConfigFilenames("strife.cfg", PROGRAM_PREFIX "strife.cfg");
+ D_BindVariables();
+ M_LoadDefaults();
+
+ if (!graphical_startup)
+ {
+ showintro = false;
+ }
+
+ // Save configuration at exit.
+ I_AtExit(M_SaveDefaults, false);
+
+ if(devparm) // [STRIFE] Devparm only
+ DEH_printf("W_Init: Init WADfiles.\n");
+ D_AddFile(iwadfile);
+ modifiedgame = W_ParseCommandLine();
+
+ // [STRIFE] serial number output
+ if(devparm)
+ {
+ char msgbuf[80];
+ char *serial = W_CacheLumpName("SERIAL", PU_CACHE);
+ int serialnum = atoi(serial);
+
+ DEH_snprintf(msgbuf, sizeof(msgbuf), "Wad Serial Number: %d:", serialnum);
+ printf("%s\n", msgbuf);
+ }
+
+ // add any files specified on the command line with -file wadfile
+ // to the wad list
+ //
+
+ // Debug:
+// W_PrintDirectory();
+
+ //!
+ // @arg <demo>
+ // @category demo
+ // @vanilla
+ //
+ // Play back the demo named demo.lmp.
+ //
+
+ p = M_CheckParmWithArgs ("-playdemo", 1);
+
+ if (!p)
+ {
+ //!
+ // @arg <demo>
+ // @category demo
+ // @vanilla
+ //
+ // Play back the demo named demo.lmp, determining the framerate
+ // of the screen.
+ //
+ p = M_CheckParmWithArgs("-timedemo", 1);
+
+ }
+
+ if (p)
+ {
+ if (!strcasecmp(myargv[p+1] + strlen(myargv[p+1]) - 4, ".lmp"))
+ {
+ strcpy(file, myargv[p + 1]);
+ }
+ else
+ {
+ sprintf (file,"%s.lmp", myargv[p+1]);
+ }
+
+ if (D_AddFile (file))
+ {
+ strncpy(demolumpname, lumpinfo[numlumps - 1].name, 8);
+ demolumpname[8] = '\0';
+
+ printf("Playing demo %s.\n", file);
+ }
+ else
+ {
+ // If file failed to load, still continue trying to play
+ // the demo in the same way as Vanilla Doom. This makes
+ // tricks like "-playdemo demo1" possible.
+
+ strncpy(demolumpname, myargv[p + 1], 8);
+ demolumpname[8] = '\0';
+ }
+
+ }
+
+ I_AtExit((atexit_func_t) G_CheckDemoStatus, true);
+
+ // Generate the WAD hash table. Speed things up a bit.
+
+ W_GenerateHashTable();
+
+ D_IdentifyVersion();
+ InitGameVersion();
+ D_SetGameDescription();
+ savegamedir = M_GetSaveGameDir("strife1.wad");
+
+ // haleyjd 20110210: Create Strife hub save folders
+ M_CreateSaveDirs(savegamedir);
+
+ I_GraphicsCheckCommandLine();
+
+ // haleyjd 20110206 [STRIFE] Startup the introduction sequence
+ D_InitIntroSequence();
+
+ // haleyjd 20110924: moved S_Init up to here
+ if(devparm) // [STRIFE]
+ DEH_printf("S_Init: Setting up sound.\n");
+ S_Init (sfxVolume * 8, musicVolume * 8, voiceVolume * 8); // [STRIFE]: voice
+ D_IntroTick(); // [STRIFE]
+
+ // 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.
+ // haleyjd 08/22/2010: [STRIFE] Check for Strife lumps.
+ char name[3][8]=
+ {
+ "map23", "map30", "ROB3E1"
+ };
+ int i;
+
+ // haleyjd 08/22/2010: [STRIFE] Changed string to match binary
+ // STRIFE-FIXME: Needs to test isdemoversion variable
+ if ( gamemode == shareware)
+ I_Error(DEH_String("\nYou cannot -file with the demo "
+ "version. You must buy the real game!"));
+
+ // Check for fake IWAD with right name,
+ // but w/o all the lumps of the registered version.
+ // STRIFE-FIXME: Needs to test isregistered variable
+ if (gamemode == registered)
+ for (i = 0; i < 3; i++)
+ if (W_CheckNumForName(name[i])<0)
+ I_Error(DEH_String("\nThis is not the registered version."));
+ }
+
+ D_IntroTick(); // [STRIFE]
+
+ // get skill / episode / map from parms
+ startskill = sk_medium;
+ startepisode = 1;
+ startmap = 1;
+ autostart = false;
+
+ //!
+ // @arg <skill>
+ // @vanilla
+ //
+ // Set the game skill, 1-5 (1: easiest, 5: hardest). A skill of
+ // 0 disables all monsters.
+ //
+
+ p = M_CheckParmWithArgs("-skill", 1);
+
+ if (p)
+ {
+ startskill = myargv[p+1][0]-'1';
+ autostart = true;
+ }
+
+ //!
+ // @arg <n>
+ // @vanilla
+ //
+ // Start playing on episode n (1-4)
+ //
+
+ p = M_CheckParmWithArgs("-episode", 1);
+
+ if (p)
+ {
+ startepisode = myargv[p+1][0]-'0';
+ startmap = 1;
+ autostart = true;
+ }
+
+ timelimit = 0;
+
+ //!
+ // @arg <n>
+ // @category net
+ // @vanilla
+ //
+ // For multiplayer games: exit each level after n minutes.
+ //
+
+ p = M_CheckParmWithArgs("-timer", 1);
+
+ if (p)
+ {
+ timelimit = atoi(myargv[p+1]);
+ printf("timer: %i\n", timelimit);
+ }
+
+ //!
+ // @category net
+ // @vanilla
+ //
+ // Austin Virtual Gaming: end levels after 20 minutes.
+ //
+
+ p = M_CheckParm ("-avg");
+
+ if (p)
+ {
+ timelimit = 20;
+ }
+
+ //!
+ // @arg [<x> <y> | <xy>]
+ // @vanilla
+ //
+ // Start a game immediately, warping to ExMy (Doom 1) or MAPxy
+ // (Doom 2)
+ //
+
+ p = M_CheckParmWithArgs("-warp", 1);
+
+ if (p)
+ {
+ if (gamemode == commercial)
+ startmap = atoi (myargv[p+1]);
+ else
+ {
+ startepisode = myargv[p+1][0]-'0';
+
+ if (p + 2 < myargc)
+ {
+ startmap = myargv[p+2][0]-'0';
+ }
+ else
+ {
+ startmap = 1;
+ }
+ }
+ autostart = true;
+ }
+
+ if (testcontrols)
+ {
+ startepisode = 1;
+ startmap = 3;
+ autostart = true;
+ }
+
+ // Check for load game parameter
+ // We do this here and save the slot number, so that the network code
+ // can override it or send the load slot to other players.
+
+ //!
+ // @arg <s>
+ // @vanilla
+ //
+ // Load the game in slot s.
+ //
+
+ p = M_CheckParmWithArgs("-loadgame", 1);
+
+ if (p)
+ {
+ startloadgame = atoi(myargv[p+1]);
+ }
+ else
+ {
+ // Not loading a game
+ startloadgame = -1;
+ }
+
+ if (W_CheckNumForName("SS_START") >= 0
+ || W_CheckNumForName("FF_END") >= 0)
+ {
+ I_PrintDivider();
+ printf(" WARNING: The loaded WAD file contains modified sprites or\n"
+ " floor textures. You may want to use the '-merge' command\n"
+ " line option instead of '-file'.\n");
+ }
+
+ I_PrintStartupBanner(gamedescription);
+ PrintDehackedBanners();
+
+ // haleyjd 08/28/10: Init Choco Strife stuff.
+ D_InitChocoStrife();
+
+ // haleyjd 08/22/2010: [STRIFE] Modified string to match binary
+ if(devparm) // [STRIFE]
+ DEH_printf("R_Init: Loading Graphics - ");
+ R_Init ();
+ D_IntroTick(); // [STRIFE]
+
+ if(devparm) // [STRIFE]
+ DEH_printf("\nP_Init: Init Playloop state.\n");
+ P_Init ();
+ D_IntroTick(); // [STRIFE]
+
+ if(devparm) // [STRIFE]
+ DEH_printf("I_Init: Setting up machine state.\n");
+ I_CheckIsScreensaver();
+ I_InitTimer();
+ I_InitJoystick();
+ D_IntroTick(); // [STRIFE]
+
+#ifdef FEATURE_MULTIPLAYER
+ if(devparm) // [STRIFE]
+ printf ("NET_Init: Init network subsystem.\n");
+ NET_Init ();
+#endif
+ D_IntroTick(); // [STRIFE]
+
+ if(devparm) // [STRIFE]
+ DEH_printf("M_Init: Init Menu.\n");
+ M_Init ();
+ D_IntroTick(); // [STRIFE]
+
+ // haleyjd 20110924: Moved S_Init up.
+ D_IntroTick();
+
+ // haleyjd 20110220: This stuff was done in I_StartupSound in vanilla, but
+ // we'll do it here instead so we don't have to modify the low-level shared
+ // code with Strife-specific stuff.
+ if(disable_voices || M_CheckParm("-novoice"))
+ {
+ dialogshowtext = disable_voices = 1;
+ }
+ if(devparm)
+ DEH_printf(" Play voices = %d\n", disable_voices == 0);
+
+ // [STRIFE]: This has been rearranged. These intro ticks occur
+ // further down in Vanilla Strife; however, we have to finish
+ // the intro sequence here so that netgame startup can begin.
+ // The original calls to D_IntroTick() are commented-out below.
+
+ // INTRO-FIXME: Great in theory but it makes the intro end too quickly.
+ // -haleyjd
+
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+ D_IntroTick();
+
+ D_FinishIntroSequence();
+
+ if(devparm) // [STRIFE]
+ DEH_printf("D_CheckNetGame: Checking network game status.\n");
+ D_CheckNetGame ();
+
+ PrintGameVersion();
+
+ if(devparm)
+ DEH_printf("HU_Init: Setting up heads up display.\n");
+ HU_Init ();
+ //D_IntroTick(); // [STRIFE]
+
+ if(devparm)
+ DEH_printf("ST_Init: Init status bar.\n");
+ ST_Init ();
+ //D_IntroTick(); // [STRIFE]
+
+ // haleyjd [STRIFE] -statcopy used to be here...
+ //D_IntroTick(); // [STRIFE]
+
+ // If Doom II without a MAP01 lump, this is a store demo.
+ // Moved this here so that MAP01 isn't constantly looked up
+ // in the main loop.
+ // haleyjd 08/23/2010: [STRIFE] There is no storedemo version of Strife
+ /*
+ if (gamemode == commercial && W_CheckNumForName("map01") < 0)
+ storedemo = true;
+ */
+
+ //!
+ // @arg <x>
+ // @category demo
+ // @vanilla
+ //
+ // Record a demo named x.lmp.
+ //
+
+ p = M_CheckParmWithArgs("-record", 1);
+
+ if (p)
+ {
+ G_RecordDemo (myargv[p+1]);
+ autostart = true;
+ }
+ //D_IntroTick(); // [STRIFE]
+
+ p = M_CheckParmWithArgs("-playdemo", 1);
+ if (p)
+ {
+ singledemo = true; // quit after one demo
+ G_DeferedPlayDemo (demolumpname);
+ D_DoomLoop (); // never returns
+ }
+ //D_IntroTick(); // [STRIFE]
+
+ p = M_CheckParmWithArgs("-timedemo", 1);
+ if (p)
+ {
+ G_TimeDemo (demolumpname);
+ D_DoomLoop (); // never returns
+ }
+ //D_IntroTick(); // [STRIFE]
+
+ if (startloadgame >= 0)
+ {
+ // [STRIFE]: different, for hubs
+ M_LoadSelect(startloadgame);
+ }
+ //D_IntroTick(); // [STRIFE]
+
+
+ if (gameaction != ga_loadgame )
+ {
+ if (autostart || netgame)
+ G_InitNew (startskill, startmap);
+ else
+ D_StartTitle (); // start up intro loop
+ }
+
+ D_DoomLoop (); // never returns
+}
diff --git a/src/strife/d_main.h b/src/strife/d_main.h
new file mode 100644
index 00000000..2909cd29
--- /dev/null
+++ b/src/strife/d_main.h
@@ -0,0 +1,64 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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_MAIN__
+#define __D_MAIN__
+
+#include "doomdef.h"
+
+
+
+
+// Read events from all input devices
+
+void D_ProcessEvents (void);
+
+
+//
+// BASE LEVEL
+//
+void D_PageTicker (void);
+void D_PageDrawer (void);
+void D_AdvanceDemo (void);
+void D_DoAdvanceDemo (void);
+void D_StartTitle (void);
+void D_QuitGame (void); // [STRIFE]
+
+void D_IntroTick(void); // [STRIFE]
+
+//
+// GLOBAL VARIABLES
+//
+
+extern gameaction_t gameaction;
+extern boolean isregistered; // villsa [STRIFE]
+extern boolean isdemoversion; // haleyjd [STRIFE]
+extern boolean stonecold; // villsa [STRIFE]
+extern boolean workparm; // villsa [STRIFE]
+
+#endif
+
diff --git a/src/strife/d_net.c b/src/strife/d_net.c
new file mode 100644
index 00000000..a3f5513c
--- /dev/null
+++ b/src/strife/d_net.c
@@ -0,0 +1,316 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 Network game communication and protocol,
+// all OS independend parts.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+
+#include "d_main.h"
+#include "m_argv.h"
+#include "m_menu.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "g_game.h"
+#include "doomdef.h"
+#include "doomstat.h"
+#include "w_checksum.h"
+
+#include "deh_main.h"
+
+#include "d_loop.h"
+
+ticcmd_t *netcmds;
+
+// Called when a player leaves the game
+
+static void PlayerQuitGame(player_t *player)
+{
+ static char exitmsg[80];
+ unsigned int player_num;
+
+ player_num = player - players;
+
+ // Do this the same way as Vanilla Doom does, to allow dehacked
+ // replacements of this message
+
+ strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg));
+ exitmsg[sizeof(exitmsg) - 1] = '\0';
+
+ exitmsg[7] += player_num;
+
+ playeringame[player_num] = false;
+ players[consoleplayer].message = exitmsg;
+
+ // TODO: check if it is sensible to do this:
+
+ if (demorecording)
+ {
+ G_CheckDemoStatus ();
+ }
+}
+
+static void RunTic(ticcmd_t *cmds, boolean *ingame)
+{
+ extern boolean advancedemo;
+ unsigned int i;
+
+ // Check for player quits.
+
+ for (i = 0; i < MAXPLAYERS; ++i)
+ {
+ if (!demoplayback && playeringame[i] && !ingame[i])
+ {
+ PlayerQuitGame(&players[i]);
+ }
+ }
+
+ netcmds = cmds;
+
+ // check that there are players in the game. if not, we cannot
+ // run a tic.
+
+ if (advancedemo)
+ D_DoAdvanceDemo ();
+
+ M_Ticker();
+ G_Ticker();
+}
+
+static void NullMenuTicker()
+{
+ // no-op.
+}
+
+static loop_interface_t strife_loop_interface = {
+ D_ProcessEvents,
+ G_BuildTiccmd,
+ RunTic,
+ NullMenuTicker
+};
+
+
+// Load game settings from the specified structure and
+// set global variables.
+
+static void LoadGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ unsigned int i;
+
+ deathmatch = settings->deathmatch;
+ ticdup = settings->ticdup;
+ startepisode = settings->episode;
+ startmap = settings->map;
+ startskill = settings->skill;
+ startloadgame = settings->loadgame;
+ lowres_turn = settings->lowres_turn;
+ nomonsters = settings->nomonsters;
+ fastparm = settings->fast_monsters;
+ respawnparm = settings->respawn_monsters;
+ timelimit = settings->timelimit;
+
+ if (lowres_turn)
+ {
+ printf("NOTE: Turning resolution is reduced; this is probably "
+ "because there is a client recording a Vanilla demo.\n");
+ }
+
+ if (!connect_data->drone)
+ {
+ consoleplayer = settings->consoleplayer;
+ }
+ else
+ {
+ consoleplayer = 0;
+ }
+
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ playeringame[i] = i < settings->num_players;
+ }
+}
+
+// Save the game settings from global variables to the specified
+// game settings structure.
+
+static void SaveGameSettings(net_gamesettings_t *settings,
+ net_connect_data_t *connect_data)
+{
+ // Fill in game settings structure with appropriate parameters
+ // for the new game
+
+ settings->deathmatch = deathmatch;
+ settings->episode = startepisode;
+ settings->map = startmap;
+ settings->skill = startskill;
+ settings->loadgame = startloadgame;
+ settings->gameversion = gameversion;
+ settings->nomonsters = nomonsters;
+ settings->fast_monsters = fastparm;
+ settings->respawn_monsters = respawnparm;
+ settings->timelimit = timelimit;
+
+ settings->lowres_turn = M_CheckParm("-record") > 0
+ && M_CheckParm("-longtics") == 0;
+
+ connect_data->drone = false;
+ connect_data->max_players = MAXPLAYERS;
+
+ //!
+ // @category net
+ //
+ // Run as the left screen in three screen mode.
+ //
+
+ if (M_CheckParm("-left") > 0)
+ {
+ viewangleoffset = ANG90;
+ connect_data->drone = true;
+ }
+
+ //!
+ // @category net
+ //
+ // Run as the right screen in three screen mode.
+ //
+
+ if (M_CheckParm("-right") > 0)
+ {
+ viewangleoffset = ANG270;
+ connect_data->drone = true;
+ }
+
+ //
+ // Connect data
+ //
+
+ // Game type fields:
+
+ connect_data->gamemode = gamemode;
+ connect_data->gamemission = gamemission;
+
+ // Are we recording a demo? Possibly set lowres turn mode
+
+ connect_data->lowres_turn = settings->lowres_turn;
+
+ // Read checksums of our WAD directory and dehacked information
+
+ W_Checksum(connect_data->wad_sha1sum);
+ DEH_Checksum(connect_data->deh_sha1sum);
+
+ connect_data->is_freedoom = 0;
+}
+
+void D_InitSinglePlayerGame(net_gamesettings_t *settings)
+{
+ // default values for single player
+
+ settings->consoleplayer = 0;
+ settings->num_players = 1;
+
+ netgame = false;
+
+ //!
+ // @category net
+ //
+ // Start the game playing as though in a netgame with a single
+ // player. This can also be used to play back single player netgame
+ // demos.
+ //
+
+ if (M_CheckParm("-solo-net") > 0)
+ {
+ netgame = true;
+ }
+}
+
+//
+// D_CheckNetGame
+// Works out player numbers among the net participants
+//
+void D_CheckNetGame (void)
+{
+ net_connect_data_t connect_data;
+ net_gamesettings_t settings;
+
+ D_RegisterLoopCallbacks(&strife_loop_interface);
+
+ // Call D_QuitNetGame on exit
+
+ I_AtExit(D_QuitNetGame, true);
+
+ SaveGameSettings(&settings, &connect_data);
+
+ if (D_InitNetGame(&connect_data, &settings))
+ {
+ netgame = true;
+ autostart = true;
+ }
+ else
+ {
+ D_InitSinglePlayerGame(&settings);
+ }
+
+ LoadGameSettings(&settings, &connect_data);
+
+ // Strife games are always deathmatch, though -altdeath is
+ // supported for respawning items.
+
+ if (netgame && deathmatch == 0)
+ {
+ deathmatch = 1;
+ }
+
+ DEH_printf("startmap: %i, skill: %i, enemies: %i, random: %i\n",
+ startmap, startskill, !nomonsters, 0 /* ??? */);
+
+
+ DEH_printf("player %i of %i (%i nodes)\n",
+ consoleplayer+1, settings.num_players, settings.num_players);
+
+ // Show players here; the server might have specified a time limit
+
+ if (timelimit > 0 && deathmatch)
+ {
+ // Gross hack to work like Vanilla:
+
+ if (timelimit == 20 && M_CheckParm("-avg"))
+ {
+ DEH_printf("Austin Virtual Gaming: Levels will end "
+ "after 20 minutes\n");
+ }
+ else
+ {
+ DEH_printf("Levels will end after %d minute", timelimit);
+ if (timelimit > 1)
+ printf("s");
+ printf(".\n");
+ }
+ }
+}
+
diff --git a/src/strife/d_player.h b/src/strife/d_player.h
new file mode 100644
index 00000000..fc4554fa
--- /dev/null
+++ b/src/strife/d_player.h
@@ -0,0 +1,257 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+//
+//
+//-----------------------------------------------------------------------------
+
+
+#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"
+
+#include "net_defs.h"
+
+
+
+
+//
+// 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,
+ // villsa [STRIFE] new cheat
+ // set when on fire and disable inventory
+ CF_ONFIRE = 8,
+ // villsa [STRIFE] new cheat
+ // auto-use medkits
+ CF_AUTOHEALTH = 16
+
+} cheat_t;
+
+// haleyjd 08/30/10: [STRIFE]
+// Player Inventory Item Structure
+typedef struct inventory_s
+{
+ int sprite; // a sprite number
+ int type; // a thing type
+ int amount; // amount being carried
+} inventory_t;
+
+#define NUMINVENTORY 32
+
+//
+// Extended player object info: player_t
+//
+// haleyjd 08/30/10: [STRIFE]
+// * Transformed to match binary structure layout.
+//
+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;
+
+ // This is only used between levels,
+ // mo->health is used during levels.
+ int health;
+ short armorpoints; // [STRIFE] Changed to short
+ // Armor type is 0-2.
+ short armortype; // [STRIFE] Changed to short
+
+ // Power ups. invinc and invis are tic counters.
+ int powers[NUMPOWERS];
+
+ // [STRIFE] Additions:
+ int sigiltype; // Type of Sigil carried
+ int nukagecount; // Nukage exposure counter
+ int questflags; // Quest bit flags
+ int pitch; // Up/down look angle
+ boolean centerview; // True if view should be centered
+ inventory_t inventory[NUMINVENTORY]; // Player inventory items
+ boolean st_update; // If true, update status bar
+ short numinventory; // Num. active inventory items
+ short inventorycursor; // Selected inventory item
+ short accuracy; // Accuracy stat
+ short stamina; // Stamina stat
+
+ boolean cards[NUMCARDS];
+ boolean backpack;
+
+ // True if button down last tic.
+ int attackdown;
+ int usedown;
+ int inventorydown; // [STRIFE] Use inventory item
+
+ // 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];
+
+ // Bit flags, for cheats and debug.
+ // See cheat_t, above.
+ int cheats;
+
+ // Refired shots are less accurate.
+ int refire;
+
+ // For intermission stats.
+ short killcount; // [STRIFE] Changed to short
+ //int itemcount; // [STRIFE] Eliminated these.
+ //int secretcount;
+
+ // Hint messages.
+ 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; [STRIFE] no such? or did it become the below?
+
+ // [STRIFE] For use of teleport beacons
+ short allegiance;
+
+ // Overlay view sprites (gun, etc).
+ pspdef_t psprites[NUMPSPRITES];
+
+ // [STRIFE] Inefficient means of tracking automap state on all maps
+ boolean mapstate[40];
+
+ // True if secret level has been done.
+ //boolean didsecret; [STRIFE] Removed this.
+
+} 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];
+
+} wbstartstruct_t;
+
+
+#endif
diff --git a/src/strife/d_textur.h b/src/strife/d_textur.h
new file mode 100644
index 00000000..084a5b1b
--- /dev/null
+++ b/src/strife/d_textur.h
@@ -0,0 +1,51 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// Typedefs related to to textures etc.,
+// isolated here to make it easier separating modules.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __D_TEXTUR__
+#define __D_TEXTUR__
+
+#include "doomtype.h"
+
+
+
+
+//
+// Flats?
+//
+// a pic is an unmasked block of pixels
+typedef struct
+{
+ byte width;
+ byte height;
+ byte data;
+} pic_t;
+
+
+
+
+#endif
diff --git a/src/strife/d_think.h b/src/strife/d_think.h
new file mode 100644
index 00000000..1405230d
--- /dev/null
+++ b/src/strife/d_think.h
@@ -0,0 +1,76 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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__
+
+
+
+
+
+//
+// Experimental stuff.
+// To compile this as "ANSI C with classes"
+// we will need to handle the various
+// action functions cleanly.
+//
+typedef void (*actionf_v)();
+typedef void (*actionf_p1)( void* );
+typedef void (*actionf_p2)( void*, void* );
+
+typedef union
+{
+ actionf_v acv;
+ actionf_p1 acp1;
+ 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;
+
+} thinker_t;
+
+
+
+#endif
diff --git a/src/strife/deh_ammo.c b/src/strife/deh_ammo.c
new file mode 100644
index 00000000..952d8df3
--- /dev/null
+++ b/src/strife/deh_ammo.c
@@ -0,0 +1,112 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Ammo" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomdef.h"
+#include "doomtype.h"
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "p_local.h"
+
+static void *DEH_AmmoStart(deh_context_t *context, char *line)
+{
+ int ammo_number = 0;
+
+ if (sscanf(line, "Ammo %i", &ammo_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (ammo_number < 0 || ammo_number >= NUMAMMO)
+ {
+ DEH_Warning(context, "Invalid ammo number: %i", ammo_number);
+ return NULL;
+ }
+
+ return &maxammo[ammo_number];
+}
+
+static void DEH_AmmoParseLine(deh_context_t *context, char *line, void *tag)
+{
+ char *variable_name, *value;
+ int ivalue;
+ int ammo_number;
+
+ if (tag == NULL)
+ return;
+
+ ammo_number = ((int *) tag) - maxammo;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ ivalue = atoi(value);
+
+ // maxammo
+
+ if (!strcasecmp(variable_name, "Per ammo"))
+ clipammo[ammo_number] = ivalue;
+ else if (!strcasecmp(variable_name, "Max ammo"))
+ maxammo[ammo_number] = ivalue;
+ else
+ {
+ DEH_Warning(context, "Field named '%s' not found", variable_name);
+ }
+}
+
+static void DEH_AmmoSHA1Hash(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ SHA1_UpdateInt32(context, clipammo[i]);
+ SHA1_UpdateInt32(context, maxammo[i]);
+ }
+}
+
+deh_section_t deh_section_ammo =
+{
+ "Ammo",
+ NULL,
+ DEH_AmmoStart,
+ DEH_AmmoParseLine,
+ NULL,
+ DEH_AmmoSHA1Hash,
+};
+
diff --git a/src/strife/deh_cheat.c b/src/strife/deh_cheat.c
new file mode 100644
index 00000000..9d3d453d
--- /dev/null
+++ b/src/strife/deh_cheat.c
@@ -0,0 +1,157 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Cheat" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "am_map.h"
+#include "st_stuff.h"
+
+typedef struct
+{
+ char *name;
+ cheatseq_t *seq;
+} deh_cheat_t;
+
+static deh_cheat_t allcheats[] =
+{
+ // haleyjd 20110224: filled in all cheats
+ {"Change music", &cheat_mus },
+ {"Level Warp", &cheat_clev },
+ {"Stealth Boots", &cheat_stealth },
+ {"Sigil piece", &cheat_lego },
+ {"FPS", &cheat_mypos },
+ {"TeleportMapSpot", &cheat_scoot },
+ {"Gold&StatTokens", &cheat_midas },
+ {"God mode", &cheat_god },
+ {"Keys", &cheat_keys },
+ {"Weapons & Ammo", &cheat_ammo },
+ {"Massacre", &cheat_nuke },
+ {"No Clipping", &cheat_noclip },
+ {"Berserk", &cheat_powerup[0] },
+ {"Invisibility", &cheat_powerup[1] },
+ {"Enviro Suit", &cheat_powerup[2] },
+ {"Health", &cheat_powerup[3] },
+ {"Backpack", &cheat_powerup[4] },
+ // STRIFE-FIXME/TODO: Does SeHackEd not support PUMPUP{S,T,nil}, or "DOTS" ?
+};
+
+static deh_cheat_t *FindCheatByName(char *name)
+{
+ size_t i;
+
+ for (i=0; i<arrlen(allcheats); ++i)
+ {
+ if (!strcasecmp(allcheats[i].name, name))
+ return &allcheats[i];
+ }
+
+ return NULL;
+}
+
+static void *DEH_CheatStart(deh_context_t *context, char *line)
+{
+ return NULL;
+}
+
+static void DEH_CheatParseLine(deh_context_t *context, char *line, void *tag)
+{
+ deh_cheat_t *cheat;
+ char *variable_name;
+ char *value;
+ unsigned char *unsvalue;
+ unsigned int i;
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ unsvalue = (unsigned char *) value;
+
+ cheat = FindCheatByName(variable_name);
+
+ if (cheat == NULL)
+ {
+ DEH_Warning(context, "Unknown cheat '%s'", variable_name);
+ return;
+ }
+
+ // write the value into the cheat sequence
+
+ i = 0;
+
+ while (unsvalue[i] != 0 && unsvalue[i] != 0xff)
+ {
+ // If the cheat length exceeds the Vanilla limit, stop. This
+ // does not apply if we have the limit turned off.
+
+ if (!deh_allow_long_cheats && i >= cheat->seq->sequence_len)
+ {
+ DEH_Warning(context, "Cheat sequence longer than supported by "
+ "Vanilla dehacked");
+ break;
+ }
+
+ if (deh_apply_cheats)
+ {
+ cheat->seq->sequence[i] = unsvalue[i];
+ }
+ ++i;
+
+ // Absolute limit - don't exceed
+
+ if (i >= MAX_CHEAT_LEN - cheat->seq->parameter_chars)
+ {
+ DEH_Error(context, "Cheat sequence too long!");
+ return;
+ }
+ }
+
+ if (deh_apply_cheats)
+ {
+ cheat->seq->sequence[i] = '\0';
+ }
+}
+
+deh_section_t deh_section_cheat =
+{
+ "Cheat",
+ NULL,
+ DEH_CheatStart,
+ DEH_CheatParseLine,
+ NULL,
+ NULL,
+};
+
diff --git a/src/strife/deh_frame.c b/src/strife/deh_frame.c
new file mode 100644
index 00000000..dc68fde5
--- /dev/null
+++ b/src/strife/deh_frame.c
@@ -0,0 +1,168 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Frame" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomtype.h"
+#include "d_items.h"
+#include "info.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+
+DEH_BEGIN_MAPPING(state_mapping, state_t)
+ DEH_MAPPING("Sprite number", sprite)
+ DEH_MAPPING("Sprite subnumber", frame)
+ DEH_MAPPING("Duration", tics)
+ DEH_MAPPING("Next frame", nextstate)
+ DEH_UNSUPPORTED_MAPPING("Action pointer")
+DEH_END_MAPPING
+
+static void *DEH_FrameStart(deh_context_t *context, char *line)
+{
+ int frame_number = 0;
+ state_t *state;
+
+ if (sscanf(line, "Frame %i", &frame_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (frame_number < 0 || frame_number >= NUMSTATES)
+ {
+ DEH_Warning(context, "Invalid frame number: %i", frame_number);
+ return NULL;
+ }
+
+ if (frame_number >= DEH_VANILLA_NUMSTATES)
+ {
+ DEH_Warning(context, "Attempt to modify frame %i: this will cause "
+ "problems in Vanilla dehacked.", frame_number);
+ }
+
+ state = &states[frame_number];
+
+ return state;
+}
+
+// Simulate a frame overflow: Doom has 967 frames in the states[] array, but
+// DOS dehacked internally only allocates memory for 966. As a result,
+// attempts to set frame 966 (the last frame) will overflow the dehacked
+// array and overwrite the weaponinfo[] array instead.
+//
+// This is noticable in Batman Doom where it is impossible to switch weapons
+// away from the fist once selected.
+
+static void DEH_FrameOverflow(deh_context_t *context, char *varname, int value)
+{
+ if (!strcasecmp(varname, "Duration"))
+ {
+ weaponinfo[0].ammo = value;
+ }
+ else if (!strcasecmp(varname, "Codep frame"))
+ {
+ weaponinfo[0].upstate = value;
+ }
+ else if (!strcasecmp(varname, "Next frame"))
+ {
+ weaponinfo[0].downstate = value;
+ }
+ else if (!strcasecmp(varname, "Unknown 1"))
+ {
+ weaponinfo[0].readystate = value;
+ }
+ else if (!strcasecmp(varname, "Unknown 2"))
+ {
+ weaponinfo[0].atkstate = value;
+ }
+ else
+ {
+ DEH_Error(context, "Unable to simulate frame overflow: field '%s'",
+ varname);
+ }
+}
+
+static void DEH_FrameParseLine(deh_context_t *context, char *line, void *tag)
+{
+ state_t *state;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ state = (state_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ if (state == &states[NUMSTATES - 1])
+ {
+ DEH_FrameOverflow(context, variable_name, ivalue);
+ }
+ else
+ {
+ // set the appropriate field
+
+ DEH_SetMapping(context, &state_mapping, state, variable_name, ivalue);
+ }
+}
+
+static void DEH_FrameSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMSTATES; ++i)
+ {
+ DEH_StructSHA1Sum(context, &state_mapping, &states[i]);
+ }
+}
+
+deh_section_t deh_section_frame =
+{
+ "Frame",
+ NULL,
+ DEH_FrameStart,
+ DEH_FrameParseLine,
+ NULL,
+ DEH_FrameSHA1Sum,
+};
+
diff --git a/src/strife/deh_misc.c b/src/strife/deh_misc.c
new file mode 100644
index 00000000..aaebbadd
--- /dev/null
+++ b/src/strife/deh_misc.c
@@ -0,0 +1,237 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Misc" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "deh_misc.h"
+
+// Dehacked: "Initial Health"
+// This is the initial health a player has when starting anew.
+// See G_PlayerReborn in g_game.c
+
+int deh_initial_health = DEH_DEFAULT_INITIAL_HEALTH;
+
+// Dehacked: "Initial bullets"
+// This is the number of bullets the player has when starting anew.
+// See G_PlayerReborn in g_game.c
+
+int deh_initial_bullets = DEH_DEFAULT_INITIAL_BULLETS;
+
+// Dehacked: "Max Health"
+// This is the maximum health that can be reached using medikits
+// alone. See P_TouchSpecialThing in p_inter.c
+
+int deh_max_health = DEH_DEFAULT_MAX_HEALTH;
+
+// Dehacked: "Max Armor"
+// This is the maximum armor which can be reached by picking up
+// armor helmets. See P_TouchSpecialThing in p_inter.c
+
+int deh_max_armor = DEH_DEFAULT_MAX_ARMOR;
+
+// Dehacked: "Green Armor Class"
+// This is the armor class that is given when picking up the green
+// armor or an armor helmet. See P_TouchSpecialThing in p_inter.c
+//
+// DOS dehacked only modifies the behavior of the green armor shirt,
+// the armor class set by armor helmets is not affected.
+
+int deh_green_armor_class = DEH_DEFAULT_GREEN_ARMOR_CLASS;
+
+// Dehacked: "Blue Armor Class"
+// This is the armor class that is given when picking up the blue
+// armor or a megasphere. See P_TouchSpecialThing in p_inter.c
+//
+// DOS dehacked only modifies the MegaArmor behavior and not
+// the MegaSphere, which always gives armor type 2.
+
+int deh_blue_armor_class = DEH_DEFAULT_BLUE_ARMOR_CLASS;
+
+// Dehacked: "Max soulsphere"
+// The maximum health which can be reached by picking up the
+// soulsphere. See P_TouchSpecialThing in p_inter.c
+
+int deh_max_soulsphere = DEH_DEFAULT_MAX_SOULSPHERE;
+
+// Dehacked: "Soulsphere health"
+// The amount of health bonus that picking up a soulsphere
+// gives. See P_TouchSpecialThing in p_inter.c
+
+int deh_soulsphere_health = DEH_DEFAULT_SOULSPHERE_HEALTH;
+
+// Dehacked: "Megasphere health"
+// This is what the health is set to after picking up a
+// megasphere. See P_TouchSpecialThing in p_inter.c
+
+int deh_megasphere_health = DEH_DEFAULT_MEGASPHERE_HEALTH;
+
+// Dehacked: "God mode health"
+// This is what the health value is set to when cheating using
+// the IDDQD god mode cheat. See ST_Responder in st_stuff.c
+
+int deh_god_mode_health = DEH_DEFAULT_GOD_MODE_HEALTH;
+
+// Dehacked: "IDFA Armor"
+// This is what the armor is set to when using the IDFA cheat.
+// See ST_Responder in st_stuff.c
+
+int deh_idfa_armor = DEH_DEFAULT_IDFA_ARMOR;
+
+// Dehacked: "IDFA Armor Class"
+// This is what the armor class is set to when using the IDFA cheat.
+// See ST_Responder in st_stuff.c
+
+int deh_idfa_armor_class = DEH_DEFAULT_IDFA_ARMOR_CLASS;
+
+// Dehacked: "IDKFA Armor"
+// This is what the armor is set to when using the IDKFA cheat.
+// See ST_Responder in st_stuff.c
+
+int deh_idkfa_armor = DEH_DEFAULT_IDKFA_ARMOR;
+
+// Dehacked: "IDKFA Armor Class"
+// This is what the armor class is set to when using the IDKFA cheat.
+// See ST_Responder in st_stuff.c
+
+int deh_idkfa_armor_class = DEH_DEFAULT_IDKFA_ARMOR_CLASS;
+
+// Dehacked: "BFG Cells/Shot"
+// This is the number of CELLs firing the BFG uses up.
+// See P_CheckAmmo and A_FireBFG in p_pspr.c
+
+int deh_bfg_cells_per_shot = DEH_DEFAULT_BFG_CELLS_PER_SHOT;
+
+// Dehacked: "Monsters infight"
+// This controls whether monsters can harm other monsters of the same
+// species. For example, whether an imp fireball will damage other
+// imps. The value of this in dehacked patches is weird - '202' means
+// off, while '221' means on.
+//
+// See PIT_CheckThing in p_map.c
+
+int deh_species_infighting = DEH_DEFAULT_SPECIES_INFIGHTING;
+
+static struct
+{
+ char *deh_name;
+ int *value;
+} misc_settings[] = {
+ {"Initial Health", &deh_initial_health},
+ {"Initial Bullets", &deh_initial_bullets},
+ {"Max Health", &deh_max_health},
+ {"Max Armor", &deh_max_armor},
+ {"LeatherArmorClass", &deh_green_armor_class},
+ {"Metal Armor Class", &deh_blue_armor_class},
+ {"Max Soulsphere", &deh_max_soulsphere},
+ {"Soulsphere Health", &deh_soulsphere_health},
+ {"Megasphere Health", &deh_megasphere_health},
+ {"God Mode Health", &deh_god_mode_health},
+ {"IDFA Armor", &deh_idfa_armor},
+ {"IDFA Armor Class", &deh_idfa_armor_class},
+ {"IDKFA Armor", &deh_idkfa_armor},
+ {"IDKFA Armor Class", &deh_idkfa_armor_class},
+ {"Mauler Cells/Shot", &deh_bfg_cells_per_shot},
+};
+
+static void *DEH_MiscStart(deh_context_t *context, char *line)
+{
+ return NULL;
+}
+
+static void DEH_MiscParseLine(deh_context_t *context, char *line, void *tag)
+{
+ char *variable_name, *value;
+ int ivalue;
+ size_t i;
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ ivalue = atoi(value);
+
+ if (!strcasecmp(variable_name, "Monsters Infight"))
+ {
+ // See notes above.
+
+ if (ivalue == 202)
+ {
+ deh_species_infighting = 0;
+ }
+ else if (ivalue == 221)
+ {
+ deh_species_infighting = 1;
+ }
+ else
+ {
+ DEH_Warning(context,
+ "Invalid value for 'Monsters Infight': %i", ivalue);
+ }
+
+ return;
+ }
+
+ for (i=0; i<arrlen(misc_settings); ++i)
+ {
+ if (!strcasecmp(variable_name, misc_settings[i].deh_name))
+ {
+ *misc_settings[i].value = ivalue;
+ return;
+ }
+ }
+
+ DEH_Warning(context, "Unknown Misc variable '%s'", variable_name);
+}
+
+static void DEH_MiscSHA1Sum(sha1_context_t *context)
+{
+ unsigned int i;
+
+ for (i=0; i<arrlen(misc_settings); ++i)
+ {
+ SHA1_UpdateInt32(context, *misc_settings[i].value);
+ }
+}
+
+deh_section_t deh_section_misc =
+{
+ "Misc",
+ NULL,
+ DEH_MiscStart,
+ DEH_MiscParseLine,
+ NULL,
+ DEH_MiscSHA1Sum,
+};
+
diff --git a/src/strife/deh_misc.h b/src/strife/deh_misc.h
new file mode 100644
index 00000000..a589b104
--- /dev/null
+++ b/src/strife/deh_misc.h
@@ -0,0 +1,92 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Misc" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#ifndef DEH_MISC_H
+#define DEH_MISC_H
+
+#include "doomfeatures.h"
+
+#define DEH_DEFAULT_INITIAL_HEALTH 100
+#define DEH_DEFAULT_INITIAL_BULLETS 50
+#define DEH_DEFAULT_MAX_HEALTH 200
+#define DEH_DEFAULT_MAX_ARMOR 200
+#define DEH_DEFAULT_GREEN_ARMOR_CLASS 1
+#define DEH_DEFAULT_BLUE_ARMOR_CLASS 2
+#define DEH_DEFAULT_MAX_SOULSPHERE 200
+#define DEH_DEFAULT_SOULSPHERE_HEALTH 100
+#define DEH_DEFAULT_MEGASPHERE_HEALTH 200
+#define DEH_DEFAULT_GOD_MODE_HEALTH 100
+#define DEH_DEFAULT_IDFA_ARMOR 200
+#define DEH_DEFAULT_IDFA_ARMOR_CLASS 2
+#define DEH_DEFAULT_IDKFA_ARMOR 200
+#define DEH_DEFAULT_IDKFA_ARMOR_CLASS 2
+#define DEH_DEFAULT_BFG_CELLS_PER_SHOT 40
+#define DEH_DEFAULT_SPECIES_INFIGHTING 0
+
+#ifdef FEATURE_DEHACKED
+
+extern int deh_initial_health;
+extern int deh_initial_bullets;
+extern int deh_max_health;
+extern int deh_max_armor;
+extern int deh_green_armor_class;
+extern int deh_blue_armor_class;
+extern int deh_max_soulsphere;
+extern int deh_soulsphere_health;
+extern int deh_megasphere_health;
+extern int deh_god_mode_health;
+extern int deh_idfa_armor;
+extern int deh_idfa_armor_class;
+extern int deh_idkfa_armor;
+extern int deh_idkfa_armor_class;
+extern int deh_bfg_cells_per_shot;
+extern int deh_species_infighting;
+
+#else
+
+// If dehacked is disabled, hard coded values
+
+#define deh_initial_health DEH_DEFAULT_INITIAL_HEALTH
+#define deh_initial_bullets DEH_DEFAULT_INITIAL_BULLETS
+#define deh_max_health DEH_DEFAULT_MAX_HEALTH
+#define deh_max_armor DEH_DEFAULT_MAX_ARMOR
+#define deh_green_armor_class DEH_DEFAULT_GREEN_ARMOR_CLASS
+#define deh_blue_armor_class DEH_DEFAULT_BLUE_ARMOR_CLASS
+#define deh_max_soulsphere DEH_DEFAULT_MAX_SOULSPHERE
+#define deh_soulsphere_health DEH_DEFAULT_SOULSPHERE_HEALTH
+#define deh_megasphere_health DEH_DEFAULT_MEGASPHERE_HEALTH
+#define deh_god_mode_health DEH_DEFAULT_GOD_MODE_HEALTH
+#define deh_idfa_armor DEH_DEFAULT_IDFA_ARMOR
+#define deh_idfa_armor_class DEH_DEFAULT_IDFA_ARMOR_CLASS
+#define deh_idkfa_armor DEH_DEFAULT_IDKFA_ARMOR
+#define deh_idkfa_armor_class DEH_DEFAULT_IDKFA_ARMOR_CLASS
+#define deh_bfg_cells_per_shot DEH_DEFAULT_BFG_CELLS_PER_SHOT
+#define deh_species_infighting DEH_DEFAULT_SPECIES_INFIGHTING
+
+#endif
+
+#endif /* #ifndef DEH_MISC_H */
+
diff --git a/src/strife/deh_ptr.c b/src/strife/deh_ptr.c
new file mode 100644
index 00000000..0d1764c9
--- /dev/null
+++ b/src/strife/deh_ptr.c
@@ -0,0 +1,151 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses Action Pointer entries in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "info.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+
+static actionf_t codeptrs[NUMSTATES];
+
+static int CodePointerIndex(actionf_t *ptr)
+{
+ int i;
+
+ for (i=0; i<NUMSTATES; ++i)
+ {
+ if (!memcmp(&codeptrs[i], ptr, sizeof(actionf_t)))
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static void DEH_PointerInit(void)
+{
+ int i;
+
+ // Initialize list of dehacked pointers
+
+ for (i=0; i<NUMSTATES; ++i)
+ codeptrs[i] = states[i].action;
+}
+
+static void *DEH_PointerStart(deh_context_t *context, char *line)
+{
+ int frame_number = 0;
+
+ // FIXME: can the third argument here be something other than "Frame"
+ // or are we ok?
+
+ if (sscanf(line, "Pointer %*i (%*s %i)", &frame_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (frame_number < 0 || frame_number >= NUMSTATES)
+ {
+ DEH_Warning(context, "Invalid frame number: %i", frame_number);
+ return NULL;
+ }
+
+ return &states[frame_number];
+}
+
+static void DEH_PointerParseLine(deh_context_t *context, char *line, void *tag)
+{
+ state_t *state;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ state = (state_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+// printf("Set %s to %s for state\n", variable_name, value);
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ // set the appropriate field
+
+ if (!strcasecmp(variable_name, "Codep frame"))
+ {
+ if (ivalue < 0 || ivalue >= NUMSTATES)
+ {
+ DEH_Warning(context, "Invalid state '%i'", ivalue);
+ }
+ else
+ {
+ state->action = codeptrs[ivalue];
+ }
+ }
+ else
+ {
+ DEH_Warning(context, "Unknown variable name '%s'", variable_name);
+ }
+}
+
+static void DEH_PointerSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMSTATES; ++i)
+ {
+ SHA1_UpdateInt32(context, CodePointerIndex(&states[i].action));
+ }
+}
+
+deh_section_t deh_section_pointer =
+{
+ "Pointer",
+ DEH_PointerInit,
+ DEH_PointerStart,
+ DEH_PointerParseLine,
+ NULL,
+ DEH_PointerSHA1Sum,
+};
+
diff --git a/src/strife/deh_sound.c b/src/strife/deh_sound.c
new file mode 100644
index 00000000..251cdccb
--- /dev/null
+++ b/src/strife/deh_sound.c
@@ -0,0 +1,112 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Sound" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+#include "doomtype.h"
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+#include "sounds.h"
+
+DEH_BEGIN_MAPPING(sound_mapping, sfxinfo_t)
+ DEH_UNSUPPORTED_MAPPING("Offset")
+ DEH_UNSUPPORTED_MAPPING("Zero/One")
+ DEH_MAPPING("Value", priority)
+ DEH_MAPPING("Zero 1", link)
+ DEH_MAPPING("Zero 2", pitch)
+ DEH_MAPPING("Zero 3", volume)
+ DEH_UNSUPPORTED_MAPPING("Zero 4")
+ DEH_MAPPING("Neg. One 1", usefulness)
+ DEH_MAPPING("Neg. One 2", lumpnum)
+DEH_END_MAPPING
+
+static void *DEH_SoundStart(deh_context_t *context, char *line)
+{
+ int sound_number = 0;
+
+ if (sscanf(line, "Sound %i", &sound_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (sound_number < 0 || sound_number >= NUMSFX)
+ {
+ DEH_Warning(context, "Invalid sound number: %i", sound_number);
+ return NULL;
+ }
+
+ if (sound_number >= DEH_VANILLA_NUMSFX)
+ {
+ DEH_Warning(context, "Attempt to modify SFX %i. This will cause "
+ "problems in Vanilla dehacked.", sound_number);
+ }
+
+ return &S_sfx[sound_number];
+}
+
+static void DEH_SoundParseLine(deh_context_t *context, char *line, void *tag)
+{
+ sfxinfo_t *sfx;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ sfx = (sfxinfo_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ // Set the field value
+
+ DEH_SetMapping(context, &sound_mapping, sfx, variable_name, ivalue);
+}
+
+deh_section_t deh_section_sound =
+{
+ "Sound",
+ NULL,
+ DEH_SoundStart,
+ DEH_SoundParseLine,
+ NULL,
+ NULL,
+};
+
diff --git a/src/strife/deh_strife.c b/src/strife/deh_strife.c
new file mode 100644
index 00000000..bda411c0
--- /dev/null
+++ b/src/strife/deh_strife.c
@@ -0,0 +1,74 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Top-level dehacked definitions for Strife dehacked (sehacked)
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include "deh_defs.h"
+#include "deh_main.h"
+
+char *deh_signatures[] =
+{
+ "Patch File for SeHackEd v0.4",
+ "Patch File for SeHackEd v0.3",
+ NULL
+};
+
+// deh_ammo.c:
+extern deh_section_t deh_section_ammo;
+// deh_cheat.c:
+extern deh_section_t deh_section_cheat;
+// deh_frame.c:
+extern deh_section_t deh_section_frame;
+// deh_misc.c:
+extern deh_section_t deh_section_misc;
+// deh_ptr.c:
+extern deh_section_t deh_section_pointer;
+// deh_sound.c
+extern deh_section_t deh_section_sound;
+// deh_text.c:
+extern deh_section_t deh_section_text;
+// deh_thing.c:
+extern deh_section_t deh_section_thing;
+// deh_weapon.c:
+extern deh_section_t deh_section_weapon;
+
+//
+// List of section types:
+//
+
+deh_section_t *deh_section_types[] =
+{
+ &deh_section_ammo,
+ &deh_section_cheat,
+ &deh_section_frame,
+ &deh_section_misc,
+ &deh_section_pointer,
+ &deh_section_sound,
+ &deh_section_text,
+ &deh_section_thing,
+ &deh_section_weapon,
+ NULL
+};
+
diff --git a/src/strife/deh_thing.c b/src/strife/deh_thing.c
new file mode 100644
index 00000000..a1c1f94d
--- /dev/null
+++ b/src/strife/deh_thing.c
@@ -0,0 +1,141 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Thing" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "doomtype.h"
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+
+#include "info.h"
+
+DEH_BEGIN_MAPPING(thing_mapping, mobjinfo_t)
+ DEH_MAPPING("ID #", doomednum)
+ DEH_MAPPING("Initial frame", spawnstate)
+ DEH_MAPPING("Hit points", spawnhealth)
+ DEH_MAPPING("First moving frame", seestate)
+ DEH_MAPPING("Alert sound", seesound)
+ DEH_MAPPING("Reaction time", reactiontime)
+ DEH_MAPPING("Attack sound", attacksound)
+ DEH_MAPPING("Injury frame", painstate)
+ DEH_MAPPING("Pain chance", painchance)
+ DEH_MAPPING("Pain sound", painsound)
+ DEH_MAPPING("Close attack frame", meleestate)
+ DEH_MAPPING("Far attack frame", missilestate)
+ DEH_MAPPING("Crash frame", crashstate)
+ DEH_MAPPING("Death frame", deathstate)
+ DEH_MAPPING("Exploding frame", xdeathstate)
+ DEH_MAPPING("Death sound", deathsound)
+ DEH_MAPPING("Speed", speed)
+ DEH_MAPPING("Width", radius)
+ DEH_MAPPING("Height", height)
+ DEH_MAPPING("Mass", mass)
+ DEH_MAPPING("Missile damage", damage)
+ DEH_MAPPING("Action sound", activesound)
+ DEH_MAPPING("Bits", flags)
+ DEH_UNSUPPORTED_MAPPING("Name pointer")
+DEH_END_MAPPING
+
+static void *DEH_ThingStart(deh_context_t *context, char *line)
+{
+ int thing_number = 0;
+ mobjinfo_t *mobj;
+
+ if (sscanf(line, "Thing %i", &thing_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ // dehacked files are indexed from 1
+ --thing_number;
+
+ if (thing_number < 0 || thing_number >= NUMMOBJTYPES)
+ {
+ DEH_Warning(context, "Invalid thing number: %i", thing_number);
+ return NULL;
+ }
+
+ mobj = &mobjinfo[thing_number];
+
+ return mobj;
+}
+
+static void DEH_ThingParseLine(deh_context_t *context, char *line, void *tag)
+{
+ mobjinfo_t *mobj;
+ char *variable_name, *value;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ mobj = (mobjinfo_t *) tag;
+
+ // Parse the assignment
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+// printf("Set %s to %s for mobj\n", variable_name, value);
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ // Set the field value
+
+ DEH_SetMapping(context, &thing_mapping, mobj, variable_name, ivalue);
+}
+
+static void DEH_ThingSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMMOBJTYPES; ++i)
+ {
+ DEH_StructSHA1Sum(context, &thing_mapping, &mobjinfo[i]);
+ }
+}
+
+deh_section_t deh_section_thing =
+{
+ "Thing",
+ NULL,
+ DEH_ThingStart,
+ DEH_ThingParseLine,
+ NULL,
+ DEH_ThingSHA1Sum,
+};
+
diff --git a/src/strife/deh_weapon.c b/src/strife/deh_weapon.c
new file mode 100644
index 00000000..67cbe5b6
--- /dev/null
+++ b/src/strife/deh_weapon.c
@@ -0,0 +1,111 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Parses "Weapon" sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "doomtype.h"
+
+#include "d_items.h"
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+
+DEH_BEGIN_MAPPING(weapon_mapping, weaponinfo_t)
+ DEH_MAPPING("Ammo type", ammo)
+ DEH_MAPPING("Deselect frame", upstate)
+ DEH_MAPPING("Select frame", downstate)
+ DEH_MAPPING("Bobbing frame", readystate)
+ DEH_MAPPING("Shooting frame", atkstate)
+ DEH_MAPPING("Firing frame", flashstate)
+ DEH_UNSUPPORTED_MAPPING("? Unknown")
+DEH_END_MAPPING
+
+static void *DEH_WeaponStart(deh_context_t *context, char *line)
+{
+ int weapon_number = 0;
+
+ if (sscanf(line, "Weapon %i", &weapon_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ if (weapon_number < 0 || weapon_number >= NUMWEAPONS)
+ {
+ DEH_Warning(context, "Invalid weapon number: %i", weapon_number);
+ return NULL;
+ }
+
+ return &weaponinfo[weapon_number];
+}
+
+static void DEH_WeaponParseLine(deh_context_t *context, char *line, void *tag)
+{
+ char *variable_name, *value;
+ weaponinfo_t *weapon;
+ int ivalue;
+
+ if (tag == NULL)
+ return;
+
+ weapon = (weaponinfo_t *) tag;
+
+ if (!DEH_ParseAssignment(line, &variable_name, &value))
+ {
+ // Failed to parse
+
+ DEH_Warning(context, "Failed to parse assignment");
+ return;
+ }
+
+ ivalue = atoi(value);
+
+ DEH_SetMapping(context, &weapon_mapping, weapon, variable_name, ivalue);
+}
+
+static void DEH_WeaponSHA1Sum(sha1_context_t *context)
+{
+ int i;
+
+ for (i=0; i<NUMWEAPONS ;++i)
+ {
+ DEH_StructSHA1Sum(context, &weapon_mapping, &weaponinfo[i]);
+ }
+}
+
+deh_section_t deh_section_weapon =
+{
+ "Weapon",
+ NULL,
+ DEH_WeaponStart,
+ DEH_WeaponParseLine,
+ NULL,
+ DEH_WeaponSHA1Sum,
+};
+
diff --git a/src/strife/doomdata.h b/src/strife/doomdata.h
new file mode 100644
index 00000000..db57a539
--- /dev/null
+++ b/src/strife/doomdata.h
@@ -0,0 +1,233 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 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"
+
+
+
+//
+// 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;
+ short 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];
+ // Front sector, towards viewer.
+ short sector;
+} 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;
+ // sidenum[1] will be -1 if one sided
+ short sidenum[2];
+} 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
+
+// villsa [STRIFE] jump over rails?
+#define ML_JUMPOVER 512
+
+// villsa [STRIFE] block flying things
+#define ML_BLOCKFLOATERS 1024
+
+// villsa [STRIFE] TODO - 25% or 75% transcluency?
+#define ML_TRANSPARENT1 2048
+
+// villsa [STRIFE] TODO - 25% or 75% transcluency?
+#define ML_TRANSPARENT2 4096
+
+
+
+
+// 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
+{
+ short numsegs;
+ // Index of first one, segs are stored sequentially.
+ short firstseg;
+} 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
+{
+ // Partition line from (x,y) to x+dx,y+dy)
+ short x;
+ 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/src/strife/doomdef.c b/src/strife/doomdef.c
new file mode 100644
index 00000000..1ad48525
--- /dev/null
+++ b/src/strife/doomdef.c
@@ -0,0 +1,36 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// DoomDef - basic defines for DOOM, e.g. Version, game mode
+// and skill level, and display parameters.
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "doomdef.h"
+
+// Location for any defines turned variables.
+
+// None.
+
+
diff --git a/src/strife/doomdef.h b/src/strife/doomdef.h
new file mode 100644
index 00000000..d48b41ee
--- /dev/null
+++ b/src/strife/doomdef.h
@@ -0,0 +1,299 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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,
+// lots of other stuff.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __DOOMDEF__
+#define __DOOMDEF__
+
+#include <stdio.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "i_timer.h"
+#include "d_mode.h"
+
+//
+// Global parameters/defines.
+//
+// DOOM version
+//
+// haleyjd 09/28/10: Replaced with Strife version
+#define STRIFE_VERSION 101
+
+// Version code for cph's longtics hack ("v1.91")
+#define DOOM_191_VERSION 111
+
+
+// Maximum players for Strife:
+#define MAXPLAYERS 8
+
+// If rangecheck is undefined,
+// most parameter validation debugging code will not be compiled
+#define RANGECHECK
+
+// 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_UNKNOWN,
+ GS_FINALE,
+ GS_DEMOSCREEN,
+} gamestate_t;
+
+typedef enum
+{
+ ga_nothing,
+ ga_loadlevel,
+ ga_newgame,
+ ga_loadgame,
+ ga_savegame,
+ ga_playdemo,
+ ga_completed,
+ ga_victory,
+ ga_worlddone,
+ ga_screenshot
+} gameaction_t;
+
+//
+// Difficulty/skill settings/filters.
+//
+
+// Skill flags.
+#define MTF_EASY 1
+#define MTF_NORMAL 2
+#define MTF_HARD 4
+// villsa [STRIFE] standing monsters
+#define MTF_STAND 8
+// villsa [STRIFE] don't spawn in single player
+#define MTF_NOTSINGLE 16
+// Deaf monsters/do not react to sound.
+#define MTF_AMBUSH 32
+// villsa [STRIFE] friendly to players
+#define MTF_FRIEND 64
+// villsa [STRIFE] TODO - identify
+#define MTF_UNKNOWN1 128
+// villsa [STRIFE] thing is translucent - STRIFE-TODO: But how much?
+#define MTF_TRANSLUCENT 256
+// villsa [STRIFE] thing is more - or less? - translucent - STRIFE-TODO
+#define MTF_MVIS 512
+// villsa [STRIFE] TODO - identify
+#define MTF_UNKNOWN2 1024
+
+
+
+//
+// Key cards.
+//
+// villsa [STRIFE]
+typedef enum
+{
+ key_BaseKey, // 0
+ key_GovsKey, // 1
+ key_Passcard, // 2
+ key_IDCard, // 3
+ key_PrisonKey, // 4
+ key_SeveredHand, // 5
+ key_Power1Key, // 6
+ key_Power2Key, // 7
+ key_Power3Key, // 8
+ key_GoldKey, // 9
+ key_IDBadge, // 10
+ key_SilverKey, // 11
+ key_OracleKey, // 12
+ key_MilitaryID, // 13
+ key_OrderKey, // 14
+ key_WarehouseKey, // 15
+ key_BrassKey, // 16
+ key_RedCrystalKey, // 17
+ key_BlueCrystalKey, // 18
+ key_ChapelKey, // 19
+ key_CatacombKey, // 20
+ key_SecurityKey, // 21
+ key_CoreKey, // 22
+ key_MaulerKey, // 23
+ key_FactoryKey, // 24
+ key_MineKey, // 25
+ key_NewKey5, // 26
+
+ NUMCARDS // 27
+} card_t;
+
+
+
+// The defined weapons,
+// including a marker indicating
+// user has not changed weapon.
+// villsa [STRIFE]
+typedef enum
+{
+ wp_fist,
+ wp_elecbow,
+ wp_rifle,
+ wp_missile,
+ wp_hegrenade,
+ wp_flame,
+ wp_mauler,
+ wp_sigil,
+ wp_poisonbow,
+ wp_wpgrenade,
+ wp_torpedo,
+
+ NUMWEAPONS,
+
+ // No pending weapon change.
+ wp_nochange
+
+} weapontype_t;
+
+
+// Ammunition types defined.
+typedef enum
+{
+ am_bullets,
+ am_elecbolts,
+ am_poisonbolts,
+ am_cell,
+ am_missiles,
+ am_hegrenades,
+ am_wpgrenades,
+
+ NUMAMMO,
+
+ am_noammo // unlimited ammo
+
+} ammotype_t;
+
+
+// Power up artifacts.
+// villsa [STRIFE]
+typedef enum
+{
+ pw_strength,
+ pw_invisibility,
+ pw_ironfeet,
+ pw_allmap,
+ pw_communicator,
+ pw_targeter,
+ NUMPOWERS
+
+} powertype_t;
+
+// villsa [STRIFE]
+// quest numbers
+typedef enum
+{ // Hex Watcom Name player_t offset
+ tk_quest1, // 0x00000001 questflags & 1 0x4D
+ tk_quest2, // 0x00000002 questflags & 2
+ tk_quest3, // 0x00000004 questflags & 4
+ tk_quest4, // 0x00000008 questflags & 8
+ tk_quest5, // 0x00000010 questflags & 10h
+ tk_quest6, // 0x00000020 questflags & 20h
+ tk_quest7, // 0x00000040 questflags & 40h
+ tk_quest8, // 0x00000080 questflags & 80h
+ tk_quest9, // 0x00000100 BYTE1(questflags) & 1 0x4E
+ tk_quest10, // 0x00000200 BYTE1(questflags) & 2
+ tk_quest11, // 0x00000400 BYTE1(questflags) & 4
+ tk_quest12, // 0x00000800 BYTE1(questflags) & 8
+ tk_quest13, // 0x00001000 BYTE1(questflags) & 10h
+ tk_quest14, // 0x00002000 BYTE1(questflags) & 20h
+ tk_quest15, // 0x00004000 BYTE1(questflags) & 40h
+ tk_quest16, // 0x00008000 BYTE1(questflags) & 80h
+ tk_quest17, // 0x00010000 BYTE2(questflags) & 1 0x4F
+ tk_quest18, // 0x00020000 BYTE2(questflags) & 2
+ tk_quest19, // 0x00040000 BYTE2(questflags) & 4
+ tk_quest20, // 0x00080000 BYTE2(questflags) & 8
+ tk_quest21, // 0x00100000 BYTE2(questflags) & 10h
+ tk_quest22, // 0x00200000 BYTE2(questflags) & 20h
+ tk_quest23, // 0x00400000 BYTE2(questflags) & 40h
+ tk_quest24, // 0x00800000 BYTE2(questflags) & 80h
+ tk_quest25, // 0x01000000 BYTE3(questflags) & 1 0x50
+ tk_quest26, // 0x02000000 BYTE3(questflags) & 2
+ tk_quest27, // 0x04000000 BYTE3(questflags) & 4
+ tk_quest28, // 0x08000000 BYTE3(questflags) & 8
+ tk_quest29, // 0x10000000 BYTE3(questflags) & 10h
+ tk_quest30, // 0x20000000 BYTE3(questflags) & 20h
+ tk_quest31, // 0x40000000 BYTE3(questflags) & 40h
+ tk_quest32, // most likely unused
+ tk_numquests
+} questtype_t;
+
+// haleyjd 09/12/10: [STRIFE]
+// flag values for each quest.
+enum
+{ // Name Flag from bitnum Purpose, if known
+ QF_QUEST1 = (1 << tk_quest1), // Obtained Beldin's ring
+ QF_QUEST2 = (1 << tk_quest2), // Stole the Chalice
+ QF_QUEST3 = (1 << tk_quest3), // Permission to visit Irale (visited Macil)
+ QF_QUEST4 = (1 << tk_quest4), // Accepted Gov. Mourel's "messy" chore
+ QF_QUEST5 = (1 << tk_quest5), // Accepted Gov. Mourel's "bloody" chore
+ QF_QUEST6 = (1 << tk_quest6), // Destroyed the Power Coupling
+ QF_QUEST7 = (1 << tk_quest7), // Killed Blue Acolytes ("Scanning Team")
+ QF_QUEST8 = (1 << tk_quest8), // Unused; formerly, picked up Broken Coupling
+ QF_QUEST9 = (1 << tk_quest9), // Obtained Derwin's ear
+ QF_QUEST10 = (1 << tk_quest10), // Obtained Prison Pass
+ QF_QUEST11 = (1 << tk_quest11), // Obtained Prison Key
+ QF_QUEST12 = (1 << tk_quest12), // Obtained Judge Wolenick's hand
+ QF_QUEST13 = (1 << tk_quest13), // Freed the Prisoners
+ QF_QUEST14 = (1 << tk_quest14), // Destroyed the Power Crystal
+ QF_QUEST15 = (1 << tk_quest15), // Obtained Guard Uniform
+ QF_QUEST16 = (1 << tk_quest16), // Destroyed the Gate Mechanism
+ QF_QUEST17 = (1 << tk_quest17), // Heard Macil's story about the Sigil (MAP10)
+ QF_QUEST18 = (1 << tk_quest18), // Obtained Oracle Pass
+ QF_QUEST19 = (1 << tk_quest19),
+ QF_QUEST20 = (1 << tk_quest20),
+ QF_QUEST21 = (1 << tk_quest21), // Killed Bishop
+ QF_QUEST22 = (1 << tk_quest22), // Killed Oracle with QUEST21 set
+ QF_QUEST23 = (1 << tk_quest23), // Killed Oracle (always given)
+ QF_QUEST24 = (1 << tk_quest24), // Killed Macil
+ QF_QUEST25 = (1 << tk_quest25), // Destroyed the Converter
+ QF_QUEST26 = (1 << tk_quest26), // Killed Loremaster
+ QF_QUEST27 = (1 << tk_quest27), // Destroyed the Computer (checked for good ending)
+ QF_QUEST28 = (1 << tk_quest28), // Obtained Catacomb Key (checked by line type 228)
+ QF_QUEST29 = (1 << tk_quest29), // Destroyed the Mines Transmitter
+ QF_QUEST30 = (1 << tk_quest30),
+ QF_QUEST31 = (1 << tk_quest31),
+ QF_QUEST32 = (1 << tk_quest32), // Unused; BUG: Broken Coupling accidentally sets it.
+
+ QF_ALLQUESTS = (QF_QUEST31 + (QF_QUEST31 - 1)) // does not include bit 32!
+};
+
+//
+// Power up durations,
+// how many seconds till expiration,
+// assuming TICRATE is 35 ticks/second.
+//
+typedef enum
+{
+ INVISTICS = (55*TICRATE), // villsa [STRIFE] changed from 60 to 55
+ IRONTICS = (80*TICRATE), // villsa [STRIFE] changed from 60 to 80
+ PMUPTICS = (80*TICRATE), // villsa [STRIFE]
+ TARGTICS = (160*TICRATE),// villsa [STRIFE]
+
+} powerduration_t;
+
+#endif // __DOOMDEF__
diff --git a/src/strife/doomstat.c b/src/strife/doomstat.c
new file mode 100644
index 00000000..df1c34ab
--- /dev/null
+++ b/src/strife/doomstat.c
@@ -0,0 +1,43 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// Put all global tate variables here.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+
+#include "doomstat.h"
+
+
+// Game Mode - identify IWAD as shareware, retail etc.
+GameMode_t gamemode = indetermined;
+GameMission_t gamemission = doom;
+GameVersion_t gameversion = exe_strife_1_31;
+char *gamedescription;
+
+// Set if homebrew PWAD stuff has been added.
+boolean modifiedgame;
+
+
+
+
diff --git a/src/strife/doomstat.h b/src/strife/doomstat.h
new file mode 100644
index 00000000..1d2d191d
--- /dev/null
+++ b/src/strife/doomstat.h
@@ -0,0 +1,286 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 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_loop.h"
+
+// We need the playr data structure as well.
+#include "d_player.h"
+
+// Game mode/mission
+#include "d_mode.h"
+
+#include "net_defs.h"
+
+
+
+// ------------------------
+// Command line parameters.
+//
+extern boolean nomonsters; // checkparm of -nomonsters
+extern boolean respawnparm; // checkparm of -respawn
+extern boolean fastparm; // checkparm of -fast
+extern boolean flipparm; // [STRIFE] checkparm of -flip
+
+extern boolean devparm; // DEBUG: launched with -devparm
+
+
+// -----------------------------------------------------
+// Game Mode - identify IWAD as shareware, retail etc.
+//
+extern GameMode_t gamemode;
+extern GameMission_t gamemission;
+extern GameVersion_t gameversion;
+extern char *gamedescription;
+
+// Set if homebrew PWAD stuff has been added.
+extern boolean modifiedgame;
+
+
+// -------------------------------------------
+// Selected skill type, map etc.
+//
+
+// Defaults for menu, methinks.
+extern skill_t startskill;
+extern int startepisode;
+extern int startmap;
+
+// Savegame slot to load on startup. This is the value provided to
+// the -loadgame option. If this has not been provided, this is -1.
+
+extern int startloadgame;
+
+extern boolean autostart;
+
+// Selected by user.
+extern skill_t gameskill;
+extern int gameepisode;
+extern int gamemap;
+
+// If non-zero, exit the level after this number of minutes
+extern int timelimit;
+
+// 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.
+
+// From m_menu.c:
+// Sound FX volume has default, 0 - 15
+// Music volume has default, 0 - 15
+// These are multiplied by 8.
+extern int sfxVolume;
+extern int musicVolume;
+extern int voiceVolume; // haleyjd 08/29/10: [STRIFE]
+
+// 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 menupause; // haleyjd 08/29/10: [STRIFE]
+extern int menupausetime; // haleyjd 09/04/10: [STRIFE]
+extern boolean menuindialog; // haleyjd: ditto
+extern boolean paused; // Game Pause?
+
+
+extern boolean viewactive;
+
+extern boolean nodrawers;
+
+extern boolean testcontrols;
+extern int testcontrols_mousespeed;
+
+
+
+
+// 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;
+//extern int totalitems; [STRIFE] unused
+extern int totalsecret;
+
+// Timer, for scores.
+extern int levelstarttic; // gametic at level start
+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;
+extern int mouse_fire_countdown; // villsa [STRIFE]
+
+// Round angleturn in ticcmds to the nearest 256. This is used when
+// recording Vanilla demos in netgames.
+
+extern boolean lowres_turn;
+
+// 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.
+
+
+// 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* deathmatch_p;
+
+// Player spawn spots.
+extern mapthing_t playerstarts[MAXPLAYERS];
+
+// haleyjd 08/24/10: [STRIFE] rift spots
+#define MAXRIFTSPOTS 16
+extern mapthing_t riftSpots[MAXRIFTSPOTS];
+
+// Intermission stats.
+// Parameters for world map / intermission.
+extern wbstartstruct_t wminfo;
+
+
+
+
+
+
+//-----------------------------------------
+// Internal parameters, used for engine.
+//
+
+// File handling stuff.
+extern char * savegamedir;
+extern char basedefault[1024];
+
+// 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;
+
+//extern int bodyqueslot; [STRIFE] unused
+
+
+
+// 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 int rndindex;
+
+extern ticcmd_t *netcmds;
+
+
+
+#endif
diff --git a/src/strife/dstrings.c b/src/strife/dstrings.c
new file mode 100644
index 00000000..01a438ae
--- /dev/null
+++ b/src/strife/dstrings.c
@@ -0,0 +1,81 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "dstrings.h"
+
+char *doom1_endmsg[] =
+{
+ "are you sure you want to\nquit this great game?",
+ "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.",
+};
+
+char *doom2_endmsg[] =
+{
+ // QuitDOOM II messages
+ "are you sure you want to\nquit this great game?",
+ "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.",
+};
+
+#if 0
+
+// UNUSED messages included in the source release
+
+char* endmsg[] =
+{
+ // DOOM1
+ QUITMSG,
+ // FinalDOOM?
+ "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."
+};
+
+#endif
+
+
+
+
diff --git a/src/strife/dstrings.h b/src/strife/dstrings.h
new file mode 100644
index 00000000..d47fc1af
--- /dev/null
+++ b/src/strife/dstrings.h
@@ -0,0 +1,49 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __DSTRINGS__
+#define __DSTRINGS__
+
+
+// All important printed strings.
+
+#include "d_englsh.h"
+
+// Misc. other strings.
+#define SAVEGAMENAME "doomsav"
+
+
+// QuitDOOM messages
+// 8 per each game type
+#define NUM_QUITMESSAGES 8
+
+extern char *doom1_endmsg[];
+extern char *doom2_endmsg[];
+
+
+#endif
diff --git a/src/strife/f_finale.c b/src/strife/f_finale.c
new file mode 100644
index 00000000..fff2aa9f
--- /dev/null
+++ b/src/strife/f_finale.c
@@ -0,0 +1,1056 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// 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.
+//
+// [STRIFE] Module marked finished 2010-09-13 22:56
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <ctype.h>
+
+// Functions.
+#include "deh_main.h"
+#include "i_system.h"
+#include "i_swap.h"
+#include "z_zone.h"
+#include "v_video.h"
+#include "w_wad.h"
+#include "s_sound.h"
+
+// Data.
+#include "d_main.h"
+#include "dstrings.h"
+#include "sounds.h"
+
+#include "doomstat.h"
+#include "r_state.h"
+
+#include "p_dialog.h" // [STRIFE]
+
+typedef enum
+{
+ F_STAGE_TEXT,
+ F_STAGE_ARTSCREEN,
+ F_STAGE_CAST,
+} finalestage_t;
+
+// ?
+//#include "doomstat.h"
+//#include "r_local.h"
+//#include "f_finale.h"
+
+// Stage of animation:
+finalestage_t finalestage;
+
+unsigned int finalecount;
+
+// haleyjd 09/12/10: [STRIFE] Slideshow variables
+char *slideshow_panel;
+unsigned int slideshow_tics;
+int slideshow_state;
+
+// haleyjd 09/13/10: [STRIFE] All this is unused.
+/*
+#define TEXTSPEED 3
+#define TEXTWAIT 250
+
+typedef struct
+{
+ GameMission_t mission;
+ int episode, level;
+ char *background;
+ char *text;
+} textscreen_t;
+
+static textscreen_t textscreens[] =
+{
+ { doom, 1, 8, "FLOOR4_8", E1TEXT},
+ { doom, 2, 8, "SFLR6_1", E2TEXT},
+ { doom, 3, 8, "MFLR8_4", E3TEXT},
+ { doom, 4, 8, "MFLR8_3", E4TEXT},
+
+ { doom2, 1, 6, "SLIME16", C1TEXT},
+ { doom2, 1, 11, "RROCK14", C2TEXT},
+ { doom2, 1, 20, "RROCK07", C3TEXT},
+ { doom2, 1, 30, "RROCK17", C4TEXT},
+ { doom2, 1, 15, "RROCK13", C5TEXT},
+ { doom2, 1, 31, "RROCK19", C6TEXT},
+
+ { pack_tnt, 1, 6, "SLIME16", T1TEXT},
+ { pack_tnt, 1, 11, "RROCK14", T2TEXT},
+ { pack_tnt, 1, 20, "RROCK07", T3TEXT},
+ { pack_tnt, 1, 30, "RROCK17", T4TEXT},
+ { pack_tnt, 1, 15, "RROCK13", T5TEXT},
+ { pack_tnt, 1, 31, "RROCK19", T6TEXT},
+
+ { pack_plut, 1, 6, "SLIME16", P1TEXT},
+ { pack_plut, 1, 11, "RROCK14", P2TEXT},
+ { pack_plut, 1, 20, "RROCK07", P3TEXT},
+ { pack_plut, 1, 30, "RROCK17", P4TEXT},
+ { pack_plut, 1, 15, "RROCK13", P5TEXT},
+ { pack_plut, 1, 31, "RROCK19", P6TEXT},
+};
+
+char* finaletext;
+char* finaleflat;
+*/
+
+void F_StartCast (void);
+void F_CastTicker (void);
+boolean F_CastResponder (event_t *ev);
+void F_CastDrawer (void);
+
+// [STRIFE] - Slideshow states enumeration
+enum
+{
+ // Exit states
+ SLIDE_EXITHACK = -99, // Hacky exit - start a new dialog
+ SLIDE_HACKHACK = -9, // Bizarre unused state
+ SLIDE_EXIT = -1, // Exit to next finale state
+ SLIDE_CHOCO = -2, // haleyjd: This state is Choco-specific... see below.
+
+ // Unknown
+ SLIDE_UNKNOWN = 0, // Dunno what it's for, possibly unused
+
+ // MAP03 - Macil's Programmer exposition
+ SLIDE_PROGRAMMER1 = 1,
+ SLIDE_PROGRAMMER2,
+ SLIDE_PROGRAMMER3,
+ SLIDE_PROGRAMMER4, // Next state = -99
+
+ // MAP10 - Macil's Sigil exposition
+ SLIDE_SIGIL1 = 5,
+ SLIDE_SIGIL2,
+ SLIDE_SIGIL3,
+ SLIDE_SIGIL4, // Next state = -99
+
+ // MAP29 - Endings
+ // Good Ending
+ SLIDE_GOODEND1 = 10,
+ SLIDE_GOODEND2,
+ SLIDE_GOODEND3,
+ SLIDE_GOODEND4, // Next state = -1
+
+ // Bad Ending
+ SLIDE_BADEND1 = 14,
+ SLIDE_BADEND2,
+ SLIDE_BADEND3, // Next state = -1
+
+ // Blah Ending
+ SLIDE_BLAHEND1 = 17,
+ SLIDE_BLAHEND2,
+ SLIDE_BLAHEND3, // Next state = -1
+
+ // Demo Ending - haleyjd 20130301: v1.31 only
+ SLIDE_DEMOEND1 = 25,
+ SLIDE_DEMOEND2 // Next state = -1
+};
+
+//
+// F_StartFinale
+//
+// [STRIFE]
+// haleyjd 09/13/10: Modified to drive slideshow sequences.
+//
+void F_StartFinale (void)
+{
+#if 0
+ // haleyjd 20111006: see below...
+ patch_t *panel;
+#endif
+
+ gameaction = ga_nothing;
+ gamestate = GS_FINALE;
+ viewactive = false;
+ automapactive = false;
+ wipegamestate = -1; // [STRIFE]
+
+ // [STRIFE] Setup the slide show
+ slideshow_panel = DEH_String("PANEL0");
+
+ // haleyjd 20111006: These two lines of code *are* in vanilla Strife;
+ // however, there, they were completely inconsequential due to the dirty
+ // rects system. No intervening V_MarkRect call means PANEL0 was never
+ // drawn to the framebuffer. In Chocolate Strife, however, with no such
+ // system in place, this only manages to fuck up the fade-out that is
+ // supposed to happen at the beginning of all finales. So, don't do it!
+#if 0
+ panel = (patch_t *)W_CacheLumpName(slideshow_panel, PU_CACHE);
+ V_DrawPatch(0, 0, panel);
+#endif
+
+ switch(gamemap)
+ {
+ case 3: // Macil's exposition on the Programmer
+ slideshow_state = SLIDE_PROGRAMMER1;
+ break;
+ case 9: // Super hack for death of Programmer
+ slideshow_state = SLIDE_EXITHACK;
+ break;
+ case 10: // Macil's exposition on the Sigil
+ slideshow_state = SLIDE_SIGIL1;
+ break;
+ case 29: // Endings
+ if(!netgame)
+ {
+ if(players[0].health <= 0) // Bad ending
+ slideshow_state = SLIDE_BADEND1; // - Humanity goes extinct
+ else
+ {
+ if((players[0].questflags & QF_QUEST25) && // Converter destroyed
+ (players[0].questflags & QF_QUEST27)) // Computer destroyed (wtf?!)
+ {
+ // Good ending - You get the hot babe.
+ slideshow_state = SLIDE_GOODEND1;
+ }
+ else
+ {
+ // Blah ending - You win the battle, but fail at life.
+ slideshow_state = SLIDE_BLAHEND1;
+ }
+ }
+ }
+ break;
+ case 34: // For the demo version ending
+ slideshow_state = SLIDE_EXIT;
+
+ // haleyjd 20130301: Somebody noticed the demo levels were missing the
+ // ending they used to have in the demo version EXE, I guess. But the
+ // weird thing is, this will only trigger if you run with strife0.wad,
+ // and no released version thereof actually works with the 1.31 EXE
+ // due to differing dialog formats... was there to be an updated demo
+ // that never got released?!
+ if(gameversion == exe_strife_1_31 && isdemoversion)
+ slideshow_state = SLIDE_DEMOEND1;
+ break;
+ }
+
+ S_ChangeMusic(mus_dark, 1);
+ slideshow_tics = 7;
+ finalestage = F_STAGE_TEXT;
+ finalecount = 0;
+}
+
+//
+// F_Responder
+//
+// [STRIFE] Verified unmodified
+//
+boolean F_Responder (event_t *event)
+{
+ if (finalestage == F_STAGE_CAST)
+ return F_CastResponder (event);
+
+ return false;
+}
+
+//
+// F_WaitTicker
+//
+// [STRIFE] New function
+// haleyjd 09/13/10: This is called from G_Ticker if gamestate is 1, but we
+// have no idea for what it's supposed to be. It is unused.
+//
+void F_WaitTicker(void)
+{
+ if(++finalecount >= 250)
+ {
+ gamestate = GS_FINALE;
+ finalestage = 0;
+ finalecount = 0;
+ }
+}
+
+//
+// F_DoSlideShow
+//
+// [STRIFE] New function
+// haleyjd 09/13/10: Handles slideshow states. Begging to be tabulated!
+//
+static void F_DoSlideShow(void)
+{
+ patch_t *patch;
+
+ switch(slideshow_state)
+ {
+ case SLIDE_UNKNOWN: // state #0, seems to be unused
+ slideshow_tics = 700;
+ slideshow_state = SLIDE_EXIT;
+ // falls through into state 1, so above is pointless? ...
+
+ case SLIDE_PROGRAMMER1: // state #1
+ slideshow_panel = DEH_String("SS2F1");
+ I_StartVoice(DEH_String("MAC10"));
+ slideshow_state = SLIDE_PROGRAMMER2;
+ slideshow_tics = 315;
+ break;
+ case SLIDE_PROGRAMMER2: // state #2
+ slideshow_panel = DEH_String("SS2F2");
+ I_StartVoice(DEH_String("MAC11"));
+ slideshow_state = SLIDE_PROGRAMMER3;
+ slideshow_tics = 350;
+ break;
+ case SLIDE_PROGRAMMER3: // state #3
+ slideshow_panel = DEH_String("SS2F3");
+ I_StartVoice(DEH_String("MAC12"));
+ slideshow_state = SLIDE_PROGRAMMER4;
+ slideshow_tics = 420;
+ break;
+ case SLIDE_PROGRAMMER4: // state #4
+ slideshow_panel = DEH_String("SS2F4");
+ I_StartVoice(DEH_String("MAC13"));
+ slideshow_state = SLIDE_EXITHACK; // End of slides
+ slideshow_tics = 595;
+ break;
+
+ case SLIDE_SIGIL1: // state #5
+ slideshow_panel = DEH_String("SS3F1");
+ I_StartVoice(DEH_String("MAC16"));
+ slideshow_state = SLIDE_SIGIL2;
+ slideshow_tics = 350;
+ break;
+ case SLIDE_SIGIL2: // state #6
+ slideshow_panel = DEH_String("SS3F2");
+ I_StartVoice(DEH_String("MAC17"));
+ slideshow_state = SLIDE_SIGIL3;
+ slideshow_tics = 420;
+ break;
+ case SLIDE_SIGIL3: // state #7
+ slideshow_panel = DEH_String("SS3F3");
+ I_StartVoice(DEH_String("MAC18"));
+ slideshow_tics = 420;
+ slideshow_state = SLIDE_SIGIL4;
+ break;
+ case SLIDE_SIGIL4: // state #8
+ slideshow_panel = DEH_String("SS3F4");
+ I_StartVoice(DEH_String("MAC19"));
+ slideshow_tics = 385;
+ slideshow_state = SLIDE_EXITHACK; // End of slides
+ break;
+
+ case SLIDE_GOODEND1: // state #10
+ slideshow_panel = DEH_String("SS4F1");
+ S_StartMusic(mus_happy);
+ I_StartVoice(DEH_String("RIE01"));
+ slideshow_state = SLIDE_GOODEND2;
+ slideshow_tics = 455;
+ break;
+ case SLIDE_GOODEND2: // state #11
+ slideshow_panel = DEH_String("SS4F2");
+ I_StartVoice(DEH_String("BBX01"));
+ slideshow_state = SLIDE_GOODEND3;
+ slideshow_tics = 385;
+ break;
+ case SLIDE_GOODEND3: // state #12
+ slideshow_panel = DEH_String("SS4F3");
+ I_StartVoice(DEH_String("BBX02"));
+ slideshow_state = SLIDE_GOODEND4;
+ slideshow_tics = 490;
+ break;
+ case SLIDE_GOODEND4: // state #13
+ slideshow_panel = DEH_String("SS4F4");
+ slideshow_state = SLIDE_EXIT; // Go to end credits
+ slideshow_tics = 980;
+ break;
+
+ case SLIDE_BADEND1: // state #14
+ S_StartMusic(mus_sad);
+ slideshow_panel = DEH_String("SS5F1");
+ I_StartVoice(DEH_String("SS501b"));
+ slideshow_state = SLIDE_BADEND2;
+ slideshow_tics = 385;
+ break;
+ case SLIDE_BADEND2: // state #15
+ slideshow_panel = DEH_String("SS5F2");
+ I_StartVoice(DEH_String("SS502b"));
+ slideshow_state = SLIDE_BADEND3;
+ slideshow_tics = 350;
+ break;
+ case SLIDE_BADEND3: // state #16
+ slideshow_panel = DEH_String("SS5F3");
+ I_StartVoice(DEH_String("SS503b"));
+ slideshow_state = SLIDE_EXIT; // Go to end credits
+ slideshow_tics = 385;
+ break;
+
+ case SLIDE_BLAHEND1: // state #17
+ S_StartMusic(mus_end);
+ slideshow_panel = DEH_String("SS6F1");
+ I_StartVoice(DEH_String("SS601A"));
+ slideshow_state = SLIDE_BLAHEND2;
+ slideshow_tics = 280;
+ break;
+ case SLIDE_BLAHEND2: // state #18
+ S_StartMusic(mus_end);
+ slideshow_panel = DEH_String("SS6F2");
+ I_StartVoice(DEH_String("SS602A"));
+ slideshow_state = SLIDE_BLAHEND3;
+ slideshow_tics = 280;
+ break;
+ case SLIDE_BLAHEND3: // state #19
+ S_StartMusic(mus_end);
+ slideshow_panel = DEH_String("SS6F3");
+ I_StartVoice(DEH_String("SS603A"));
+ slideshow_state = SLIDE_EXIT; // Go to credits
+ slideshow_tics = 315;
+ break;
+
+ case SLIDE_DEMOEND1: // state #25 - only exists in 1.31
+ slideshow_panel = DEH_String("PANEL7");
+ slideshow_tics = 175;
+ slideshow_state = SLIDE_DEMOEND2;
+ break;
+ case SLIDE_DEMOEND2: // state #26 - ditto
+ slideshow_panel = DEH_String("VELLOGO");
+ slideshow_tics = 175;
+ slideshow_state = SLIDE_EXIT; // Go to end credits
+ break;
+
+ case SLIDE_EXITHACK: // state -99: super hack state
+ gamestate = GS_LEVEL;
+ P_DialogStartP1();
+ break;
+ case SLIDE_HACKHACK: // state -9: unknown bizarre unused state
+ S_StartSound(NULL, sfx_rifle);
+ slideshow_tics = 3150;
+ break;
+ case SLIDE_EXIT: // state -1: proceed to next finale stage
+ finalecount = 0;
+ finalestage = F_STAGE_ARTSCREEN;
+ wipegamestate = -1;
+ S_StartMusic(mus_fast);
+ // haleyjd 20130301: The ONLY glitch fixed in 1.31 of Strife
+ // *would* be something this insignificant, of course!
+ if(gameversion != exe_strife_1_31)
+ slideshow_state = SLIDE_CHOCO; // haleyjd: see below...
+ break;
+ case SLIDE_CHOCO:
+ // haleyjd 09/14/10: This wouldn't be necessary except that Choco
+ // doesn't support the V_MarkRect dirty rectangles system. This
+ // just so happens to have hidden the fact that the ending
+ // does a screenfade every ~19 seconds due to remaining stuck in
+ // SLIDE_EXIT state above, UNLESS the menus were active - the
+ // V_MarkRect calls in the menu system cause it to be visible.
+ // This means that in order to get the same behavior as the vanilla
+ // EXE, I need different code. So, come to this state and only set
+ // wipegamestate if menuactive is true.
+ finalecount = 0;
+ finalestage = F_STAGE_ARTSCREEN;
+ if(menuactive)
+ wipegamestate = -1;
+ S_StartMusic(mus_fast);
+ slideshow_state = SLIDE_CHOCO; // remain here.
+ break;
+ default:
+ break;
+ }
+
+ finalecount = 0;
+ if(gameversion != exe_strife_1_31) // See above. This was removed in 1.31.
+ {
+ patch = (patch_t *)W_CacheLumpName(DEH_String("PANEL0"), PU_CACHE);
+ V_DrawPatch(0, 0, patch);
+ }
+}
+
+//
+// F_Ticker
+//
+// [STRIFE] Modifications for new finales
+// haleyjd 09/13/10: Calls F_DoSlideShow
+//
+void F_Ticker (void)
+{
+ size_t i;
+
+ // check for skipping
+ if (finalecount > 50) // [STRIFE] No commercial check
+ {
+ // go on to the next level
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ if (players[i].cmd.buttons)
+ break;
+
+ if (i < MAXPLAYERS)
+ finalecount = slideshow_tics; // [STRIFE]
+ }
+
+ // advance animation
+ finalecount++;
+
+ if (finalestage == F_STAGE_CAST)
+ F_CastTicker ();
+ else if(finalecount > slideshow_tics) // [STRIFE] Advance slideshow
+ F_DoSlideShow();
+
+ // [STRIFE]: Rest is unused
+ /*
+ if ( gamemode == commercial)
+ return;
+
+ if (finalestage == F_STAGE_TEXT
+ && finalecount>strlen (finaletext)*TEXTSPEED + TEXTWAIT)
+ {
+ finalecount = 0;
+ finalestage = F_STAGE_ARTSCREEN;
+ wipegamestate = -1; // force a wipe
+ if (gameepisode == 3)
+ S_StartMusic (mus_logo);
+ }
+ */
+}
+
+// haleyjd 09/13/10: Not present in Strife: Cast drawing functions
+
+#include "hu_stuff.h"
+extern patch_t *hu_font[HU_FONTSIZE];
+
+/*
+//
+// F_TextWrite
+//
+void F_TextWrite (void)
+{
+ byte* src;
+ byte* dest;
+
+ int x,y,w;
+ signed int count;
+ char* ch;
+ int c;
+ int cx;
+ int cy;
+
+ // erase the entire screen to a tiled background
+ src = W_CacheLumpName ( finaleflat , PU_CACHE);
+ dest = I_VideoBuffer;
+
+ for (y=0 ; y<SCREENHEIGHT ; y++)
+ {
+ for (x=0 ; x<SCREENWIDTH/64 ; x++)
+ {
+ memcpy (dest, src+((y&63)<<6), 64);
+ dest += 64;
+ }
+ if (SCREENWIDTH&63)
+ {
+ memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
+ dest += (SCREENWIDTH&63);
+ }
+ }
+
+ V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
+
+ // draw some of the text onto the screen
+ cx = 10;
+ cy = 10;
+ ch = finaletext;
+
+ count = ((signed int) finalecount - 10) / TEXTSPEED;
+ if (count < 0)
+ count = 0;
+ for ( ; count ; count-- )
+ {
+ 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;
+ V_DrawPatch(cx, cy, hu_font[c]);
+ cx+=w;
+ }
+
+}
+*/
+
+//
+// Final DOOM 2 animation
+// Casting by id Software.
+// in order of appearance
+//
+typedef struct
+{
+ int isindemo; // [STRIFE] Changed from name, which is in mobjinfo
+ mobjtype_t type;
+} castinfo_t;
+
+// haleyjd: [STRIFE] A new cast order was defined, however it is unused in any
+// of the released versions of Strife, even including the demo version :(
+castinfo_t castorder[] = {
+ { 1, MT_PLAYER },
+ { 1, MT_BEGGAR1 },
+ { 1, MT_PEASANT2_A },
+ { 1, MT_REBEL1 },
+ { 1, MT_GUARD1 },
+ { 1, MT_CRUSADER },
+ { 1, MT_RLEADER2 },
+ { 0, MT_SENTINEL },
+ { 0, MT_STALKER },
+ { 0, MT_PROGRAMMER },
+ { 0, MT_REAVER },
+ { 0, MT_PGUARD },
+ { 0, MT_INQUISITOR },
+ { 0, MT_PRIEST },
+ { 0, MT_SPECTRE_A },
+ { 0, MT_BISHOP },
+ { 0, MT_ENTITY },
+ { 1, NUMMOBJTYPES }
+};
+
+int castnum;
+int casttics;
+state_t* caststate;
+boolean castdeath;
+int castframes;
+int castonmelee;
+boolean castattacking;
+
+//
+// F_StartCast
+//
+// haleyjd 09/13/10: [STRIFE] Heavily modified, yet unused.
+// Evidence suggests this was meant to be started from a menu item.
+// See m_menu.c for more info.
+//
+void F_StartCast (void)
+{
+ usergame = false;
+ gameaction = ga_nothing;
+ viewactive = false;
+ automapactive = false;
+ castnum = 0;
+ gamestate = GS_FINALE;
+ caststate = &states[mobjinfo[castorder[castnum].type].seestate];
+ casttics = caststate->tics;
+ if(casttics > 50)
+ casttics = 50;
+ wipegamestate = -1; // force a screen wipe
+ castdeath = false;
+ finalestage = F_STAGE_CAST;
+ castframes = 0;
+ castonmelee = 0;
+ castattacking = false;
+}
+
+
+//
+// F_CastTicker
+//
+// [STRIFE] Heavily modified, but unused.
+// haleyjd 09/13/10: Yeah, I bothered translating this even though it isn't
+// going to be seen, in part because I hope some Strife port or another will
+// pick it up and finish it, adding it as the optional menu item it was
+// meant to be, or just adding it as part of the ending sequence.
+//
+void F_CastTicker (void)
+{
+ int st;
+
+ 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 (isdemoversion)
+ {
+ // [STRIFE] Demo version had a shorter cast
+ if(!castorder[castnum].isindemo)
+ castnum = 0;
+ }
+ // [STRIFE] Break on type == NUMMOBJTYPES rather than name == NULL
+ if (castorder[castnum].type == NUMMOBJTYPES)
+ 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
+ {
+ int sfx = 0;
+
+ // just advance to next state in animation
+ if (caststate == &states[S_PLAY_05]) // villsa [STRIFE] - updated
+ goto stopattack; // Oh, gross hack!
+ st = caststate->nextstate;
+ caststate = &states[st];
+ castframes++;
+
+ if (st != mobjinfo[castorder[castnum].type].meleestate &&
+ st != mobjinfo[castorder[castnum].type].missilestate)
+ {
+ if (st == S_PLAY_05)
+ sfx = sfx_rifle;
+ else
+ sfx = 0;
+ }
+ else
+ sfx = mobjinfo[castorder[castnum].type].attacksound;
+
+ if (sfx)
+ S_StartSound (NULL, sfx);
+ }
+
+ if (!castdeath && 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 > 50) // [STRIFE] Cap tics
+ casttics = 50;
+ else if (casttics == -1)
+ casttics = 15;
+}
+
+
+//
+// F_CastResponder
+//
+// [STRIFE] This still exists in Strife but is never used.
+// It was used at some point in development, however, as they made
+// numerous modifications to the cast call system.
+//
+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;
+ if(casttics > 50) // [STRIFE] Upper bound on casttics
+ casttics = 50;
+ castframes = 0;
+ castattacking = false;
+ if (mobjinfo[castorder[castnum].type].deathsound)
+ S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound);
+
+ return true;
+}
+
+//
+// F_CastPrint
+//
+// [STRIFE] Verified unmodified, and unused.
+//
+void F_CastPrint (char* text)
+{
+ char* ch;
+ 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);
+ V_DrawPatch(cx, 180, hu_font[c]);
+ cx+=w;
+ }
+
+}
+
+// haleyjd 09/13/10: [STRIFE] Unfortunately they removed whatever was
+// partway finished of this function from the binary, as there is no
+// trace of it. This means we cannot know for sure what the cast call
+// would have looked like. :(
+/*
+//
+// F_CastDrawer
+//
+void F_CastDrawer (void)
+{
+ spritedef_t* sprdef;
+ spriteframe_t* sprframe;
+ int lump;
+ boolean flip;
+ patch_t* patch;
+
+ // erase the entire screen to a background
+ V_DrawPatch (0, 0, W_CacheLumpName (DEH_String("BOSSBACK"), PU_CACHE));
+
+ F_CastPrint (DEH_String(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];
+
+ patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE);
+ if (flip)
+ V_DrawPatchFlipped(160, 170, patch);
+ else
+ V_DrawPatch(160, 170, patch);
+}
+*/
+
+#ifdef STRIFE_DEMO_CODE
+//
+// F_DrawPatchCol
+//
+// [STRIFE] Verified unmodified, but not present in 1.2
+// It WAS present in the demo version, however...
+//
+void
+F_DrawPatchCol
+( int x,
+ patch_t* patch,
+ int col )
+{
+ column_t* column;
+ byte* source;
+ byte* dest;
+ byte* desttop;
+ int count;
+
+ column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
+ desttop = I_VideoBuffer + x;
+
+ // step through the posts in a column
+ while (column->topdelta != 0xff )
+ {
+ source = (byte *)column + 3;
+ dest = desttop + column->topdelta*SCREENWIDTH;
+ count = column->length;
+
+ while (count--)
+ {
+ *dest = *source++;
+ dest += SCREENWIDTH;
+ }
+ column = (column_t *)( (byte *)column + column->length + 4 );
+ }
+}
+#endif
+
+//
+// F_DrawMap34End
+//
+// [STRIFE] Modified from F_BunnyScroll
+// * In 1.2 and up this just causes a weird black screen.
+// * In the demo version, it was an actual scroll between two screens.
+// I have implemented both code segments, though only the black screen
+// one will currently be used, as full demo version support isn't looking
+// likely right now.
+//
+void F_DrawMap34End (void)
+{
+ signed int scrolled;
+ int x;
+ patch_t* p1;
+ patch_t* p2;
+
+ p1 = W_CacheLumpName (DEH_String("credit"), PU_LEVEL);
+ p2 = W_CacheLumpName (DEH_String("vellogo"), PU_LEVEL);
+
+ V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
+
+
+ scrolled = (320 - ((signed int) finalecount-430)/2);
+ if (scrolled > 320)
+ scrolled = 320;
+ if (scrolled < 0)
+ scrolled = 0;
+
+#ifdef STRIFE_DEMO_CODE
+ for ( x=0 ; x<SCREENWIDTH ; x++)
+ {
+ if (x+scrolled < 320)
+ F_DrawPatchCol (x, p1, x+scrolled);
+ else
+ F_DrawPatchCol (x, p2, x+scrolled - 320);
+ }
+#else
+ // wtf this is supposed to do, I have no idea!
+ x = 1;
+ do
+ {
+ x += 11;
+ }
+ while(x < 320);
+#endif
+}
+
+// haleyjd 09/13/10: [STRIFE] Unused.
+/*
+static void F_ArtScreenDrawer(void)
+{
+ char *lumpname;
+
+ if (gameepisode == 3)
+ {
+ F_BunnyScroll();
+ }
+ else
+ {
+ switch (gameepisode)
+ {
+ case 1:
+ if (gamemode == retail)
+ {
+ lumpname = "CREDIT";
+ }
+ else
+ {
+ lumpname = "HELP2";
+ }
+ break;
+ case 2:
+ lumpname = "VICTORY2";
+ break;
+ case 4:
+ lumpname = "ENDPIC";
+ break;
+ default:
+ return;
+ }
+
+ lumpname = DEH_String(lumpname);
+
+ V_DrawPatch (0, 0, W_CacheLumpName(lumpname, PU_CACHE));
+ }
+}
+*/
+
+//
+// F_Drawer
+//
+// [STRIFE]
+// haleyjd 09/13/10: Modified for slideshow, demo version, etc.
+//
+void F_Drawer (void)
+{
+ switch (finalestage)
+ {
+ case F_STAGE_CAST:
+ // Cast didn't have a drawer in any released version
+ //F_CastDrawer();
+ break;
+ case F_STAGE_TEXT:
+ // Draw slideshow panel
+ {
+ patch_t *slide = W_CacheLumpName(slideshow_panel, PU_CACHE);
+ V_DrawPatch(0, 0, slide);
+ }
+ break;
+ case F_STAGE_ARTSCREEN:
+ if(gamemap <= 29)
+ {
+ // draw credits
+ patch_t *credits = W_CacheLumpName(DEH_String("CREDIT"), PU_CACHE);
+ V_DrawPatch(0, 0, credits);
+ }
+ else if(gamemap == 34)
+ {
+ // demo version - does nothing meaningful in the final version
+ F_DrawMap34End();
+ }
+ break;
+ }
+}
+
diff --git a/src/strife/f_finale.h b/src/strife/f_finale.h
new file mode 100644
index 00000000..d803a885
--- /dev/null
+++ b/src/strife/f_finale.h
@@ -0,0 +1,56 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+//
+//
+//-----------------------------------------------------------------------------
+
+
+#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);
+
+// haleyjd: [STRIFE] Called from G_Ticker as well...
+void F_WaitTicker(void);
+
+// Called by main loop.
+void F_Drawer (void);
+
+
+void F_StartFinale (void);
+
+
+
+
+#endif
diff --git a/src/strife/f_wipe.c b/src/strife/f_wipe.c
new file mode 100644
index 00000000..2d2ac3bd
--- /dev/null
+++ b/src/strife/f_wipe.c
@@ -0,0 +1,300 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <string.h>
+
+#include "z_zone.h"
+#include "i_video.h"
+#include "v_video.h"
+#include "m_random.h"
+
+#include "doomtype.h"
+
+#include "r_defs.h" // haleyjd [STRIFE]
+#include "r_draw.h"
+
+#include "f_wipe.h"
+
+//
+// SCREEN WIPE PACKAGE
+//
+
+// when zero, stop the wipe
+static boolean go = 0;
+
+static byte* wipe_scr_start;
+static byte* wipe_scr_end;
+static byte* wipe_scr;
+
+
+void
+wipe_shittyColMajorXform
+( short* array,
+ int width,
+ int height )
+{
+ int x;
+ int y;
+ short* dest;
+
+ dest = (short*) Z_Malloc(width*height*2, PU_STATIC, 0);
+
+ 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*2);
+
+ Z_Free(dest);
+
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+int
+wipe_initColorXForm
+( int width,
+ int height,
+ int ticks )
+{
+ memcpy(wipe_scr, wipe_scr_start, width*height);
+ return 0;
+}
+
+//
+// wipe_doColorXForm
+//
+// haleyjd 08/26/10: [STRIFE]
+// * Rogue modified the unused ColorXForm wipe in-place in order to implement
+// their distinctive crossfade wipe.
+//
+int
+wipe_doColorXForm
+( int width,
+ int height,
+ int ticks )
+{
+ byte *cur_screen = wipe_scr;
+ byte *end_screen = wipe_scr_end;
+ int pix = width*height;
+ int i;
+ boolean changed = false;
+
+ for(i = pix; i > 0; i--)
+ {
+ if(*cur_screen != *end_screen)
+ {
+ changed = true;
+ *cur_screen = xlatab[(*cur_screen << 8) + *end_screen];
+ }
+ ++cur_screen;
+ ++end_screen;
+ }
+
+ return !changed;
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+int
+wipe_exitColorXForm
+( int width,
+ int height,
+ int ticks )
+{
+ return 0;
+}
+
+
+static int* y;
+
+int
+wipe_initMelt
+( int width,
+ int height,
+ int ticks )
+{
+ int i, r;
+
+ // 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 *) Z_Malloc(width*sizeof(int), PU_STATIC, 0);
+ y[0] = -(M_Random()%16);
+ for (i=1;i<width;i++)
+ {
+ 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;
+}
+
+int
+wipe_doMelt
+( int width,
+ int height,
+ int ticks )
+{
+ int i;
+ int j;
+ int dy;
+ int idx;
+
+ short* s;
+ short* d;
+ boolean done = true;
+
+ width/=2;
+
+ while (ticks--)
+ {
+ for (i=0;i<width;i++)
+ {
+ if (y[i]<0)
+ {
+ y[i]++; done = false;
+ }
+ else if (y[i] < height)
+ {
+ 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;
+
+}
+
+int
+wipe_exitMelt
+( int width,
+ int height,
+ int ticks )
+{
+ Z_Free(y);
+ Z_Free(wipe_scr_start);
+ Z_Free(wipe_scr_end);
+ return 0;
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+int
+wipe_StartScreen
+( int x,
+ int y,
+ int width,
+ int height )
+{
+ wipe_scr_start = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
+ I_ReadScreen(wipe_scr_start);
+ return 0;
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+int
+wipe_EndScreen
+( int x,
+ int y,
+ int width,
+ int height )
+{
+ wipe_scr_end = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
+ I_ReadScreen(wipe_scr_end);
+ V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr.
+ return 0;
+}
+
+// haleyjd 08/26/10: [STRIFE] Verified unmodified.
+int
+wipe_ScreenWipe
+( int wipeno,
+ int x,
+ int y,
+ int width,
+ int height,
+ int ticks )
+{
+ int rc;
+ static int (*wipes[])(int, int, int) =
+ {
+ wipe_initColorXForm, wipe_doColorXForm, wipe_exitColorXForm,
+ wipe_initMelt, wipe_doMelt, wipe_exitMelt
+ };
+
+ // initial stuff
+ if (!go)
+ {
+ go = 1;
+ // haleyjd 20110629 [STRIFE]: We *must* use a temp buffer here.
+ wipe_scr = (byte *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG
+ //wipe_scr = I_VideoBuffer;
+ (*wipes[wipeno*3])(width, height, ticks);
+ }
+
+ // do a piece of wipe-in
+ V_MarkRect(0, 0, width, height);
+ rc = (*wipes[wipeno*3+1])(width, height, ticks);
+
+ // haleyjd 20110629 [STRIFE]: Copy temp buffer to the real screen.
+ V_DrawBlock(x, y, width, height, wipe_scr);
+
+ // final stuff
+ if (rc)
+ {
+ go = 0;
+ (*wipes[wipeno*3+2])(width, height, ticks);
+ }
+
+ return !go;
+}
+
diff --git a/src/strife/f_wipe.h b/src/strife/f_wipe.h
new file mode 100644
index 00000000..3f2e73af
--- /dev/null
+++ b/src/strife/f_wipe.h
@@ -0,0 +1,71 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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
+//
+
+enum
+{
+ // [STRIFE]: ColorXForm reimplemented as a proper crossfade
+ wipe_ColorXForm,
+
+ // weird screen melt
+ wipe_Melt,
+
+ wipe_NUMWIPES
+};
+
+int
+wipe_StartScreen
+( int x,
+ int y,
+ int width,
+ int height );
+
+
+int
+wipe_EndScreen
+( int x,
+ int y,
+ int width,
+ int height );
+
+
+int
+wipe_ScreenWipe
+( int wipeno,
+ int x,
+ int y,
+ int width,
+ int height,
+ int ticks );
+
+#endif
diff --git a/src/strife/g_game.c b/src/strife/g_game.c
new file mode 100644
index 00000000..e295b858
--- /dev/null
+++ b/src/strife/g_game.c
@@ -0,0 +1,2456 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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
+//
+//-----------------------------------------------------------------------------
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "doomdef.h"
+#include "doomkeys.h"
+#include "doomstat.h"
+
+#include "deh_main.h"
+#include "deh_misc.h"
+#include "z_zone.h"
+#include "f_finale.h"
+#include "m_argv.h"
+#include "m_controls.h"
+#include "m_misc.h"
+#include "m_menu.h"
+#include "m_saves.h" // STRIFE
+#include "m_random.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.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 "p_local.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_dialog.h" // villsa [STRIFE]
+
+#include "g_game.h"
+
+
+#define SAVEGAMESIZE 0x2c000
+
+void G_ReadDemoTiccmd (ticcmd_t* cmd);
+void G_WriteDemoTiccmd (ticcmd_t* cmd);
+void G_PlayerReborn (int player);
+
+void G_DoReborn (int playernum);
+
+void G_DoLoadLevel (void);
+void G_DoNewGame (void);
+void G_DoPlayDemo (void);
+void G_DoCompleted (void);
+void G_DoVictory (void);
+void G_DoWorldDone (void);
+void G_DoSaveGame (char *path);
+
+// Gamestate the last time G_Ticker was called.
+
+gamestate_t oldgamestate;
+
+gameaction_t gameaction;
+gamestate_t gamestate;
+skill_t gameskill = 2; // [STRIFE] Default value set to 2.
+boolean respawnmonsters;
+//int gameepisode;
+int gamemap;
+
+// haleyjd 08/24/10: [STRIFE] New variables
+int destmap; // current destination map when exiting
+int riftdest; // destination spot for player
+angle_t riftangle; // player angle saved during exit
+
+// If non-zero, exit the level after this number of minutes.
+
+int timelimit;
+
+boolean paused;
+boolean sendpause; // send a pause event next tic
+boolean sendsave; // send a save event next tic
+boolean usergame; // ok to save / end game
+
+boolean timingdemo; // if true, exit with report on completion
+boolean nodrawers; // for comparative timing purposes
+int starttime; // for comparative timing purposes
+
+boolean viewactive;
+
+boolean deathmatch; // only if started as net death
+boolean netgame; // only true if packets are broadcast
+boolean playeringame[MAXPLAYERS];
+player_t players[MAXPLAYERS];
+
+boolean turbodetected[MAXPLAYERS];
+
+int consoleplayer; // player taking events and displaying
+int displayplayer; // view being displayed
+int gametic;
+int levelstarttic; // gametic at level start
+int totalkills, /*totalitems,*/ totalsecret; // for intermission
+
+char *demoname;
+boolean demorecording;
+boolean longtics; // cph's doom 1.91 longtics hack
+boolean lowres_turn; // low resolution turning for longtics
+boolean demoplayback;
+boolean netdemo;
+byte* demobuffer;
+byte* demo_p;
+byte* demoend;
+boolean singledemo; // quit after playing a demo from cmdline
+
+boolean precache = true; // if true, load all graphics at start
+
+boolean testcontrols = false; // Invoked by setup to test controls
+
+wbstartstruct_t wminfo; // parms for world map / intermission
+
+byte consistancy[MAXPLAYERS][BACKUPTICS];
+
+#define MAXPLMOVE (forwardmove[1])
+
+#define TURBOTHRESHOLD 0x32
+
+fixed_t forwardmove[2] = {0x19, 0x32};
+fixed_t sidemove[2] = {0x18, 0x28};
+fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn
+
+int mouse_fire_countdown = 0; // villsa [STRIFE]
+
+static int *weapon_keys[] = {
+ &key_weapon1,
+ &key_weapon2,
+ &key_weapon3,
+ &key_weapon4,
+ &key_weapon5,
+ &key_weapon6,
+ &key_weapon7,
+ &key_weapon8
+};
+
+// Set to -1 or +1 to switch to the previous or next weapon.
+
+static int next_weapon = 0;
+
+// Used for prev/next weapon keys.
+// STRIFE-TODO: Check this table makes sense.
+
+static const struct
+{
+ weapontype_t weapon;
+ weapontype_t weapon_num;
+} weapon_order_table[] = {
+ { wp_fist, wp_fist },
+ { wp_poisonbow, wp_elecbow },
+ { wp_elecbow, wp_elecbow },
+ { wp_rifle, wp_rifle },
+ { wp_missile, wp_missile },
+ { wp_wpgrenade, wp_hegrenade },
+ { wp_hegrenade, wp_hegrenade },
+ { wp_flame, wp_flame },
+ { wp_torpedo, wp_mauler },
+ { wp_mauler, wp_mauler },
+ { wp_sigil, wp_sigil },
+};
+
+#define SLOWTURNTICS 6
+
+#define NUMKEYS 256
+#define MAX_JOY_BUTTONS 20
+
+static boolean gamekeydown[NUMKEYS];
+static int turnheld; // for accelerative turning
+
+static boolean mousearray[MAX_MOUSE_BUTTONS + 1];
+static boolean *mousebuttons = &mousearray[1]; // allow [-1]
+
+// mouse values are used once
+int mousex;
+int mousey;
+
+static int dclicktime;
+static boolean dclickstate;
+static int dclicks;
+static int dclicktime2;
+static boolean dclickstate2;
+static int dclicks2;
+
+// joystick values are repeated
+static int joyxmove;
+static int joyymove;
+static boolean joyarray[MAX_JOY_BUTTONS + 1];
+static boolean *joybuttons = &joyarray[1]; // allow [-1]
+
+static int savegameslot = 6; // [STRIFE] initialized to 6
+static char savedescription[32];
+
+int testcontrols_mousespeed;
+
+#define BODYQUESIZE 32
+
+mobj_t* bodyque[BODYQUESIZE];
+//int bodyqueslot; [STRIFE] unused
+
+int vanilla_savegame_limit = 1;
+int vanilla_demo_limit = 1;
+
+
+int G_CmdChecksum (ticcmd_t* cmd)
+{
+ size_t i;
+ int sum = 0;
+
+ for (i=0 ; i< sizeof(*cmd)/4 - 1 ; i++)
+ sum += ((int *)cmd)[i];
+
+ return sum;
+}
+
+static boolean WeaponSelectable(weapontype_t weapon)
+{
+ player_t *player;
+
+ player = &players[consoleplayer];
+
+ // Can't select a weapon if we don't own it.
+
+ if (!player->weaponowned[weapon])
+ {
+ return false;
+ }
+
+ // Can't use registered-only weapons in demo mode:
+
+ if (isdemoversion && !weaponinfo[weapon].availabledemo)
+ {
+ return false;
+ }
+
+ // Special rules for switching to alternate versions of weapons.
+ // These must match the weapon-switching rules in P_PlayerThink()
+
+ if (weapon == wp_torpedo
+ && player->ammo[weaponinfo[am_cell].ammo] < 30)
+ {
+ return false;
+ }
+
+ if (player->ammo[weaponinfo[weapon].ammo] == 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static int G_NextWeapon(int direction)
+{
+ weapontype_t weapon;
+ int i;
+
+ // Find index in the table.
+
+ if (players[consoleplayer].pendingweapon == wp_nochange)
+ {
+ weapon = players[consoleplayer].readyweapon;
+ }
+ else
+ {
+ weapon = players[consoleplayer].pendingweapon;
+ }
+
+ for (i=0; i<arrlen(weapon_order_table); ++i)
+ {
+ if (weapon_order_table[i].weapon == weapon)
+ {
+ break;
+ }
+ }
+
+ // Switch weapon.
+
+ do
+ {
+ i += direction;
+ i = (i + arrlen(weapon_order_table)) % arrlen(weapon_order_table);
+ } while (!WeaponSelectable(weapon_order_table[i].weapon));
+
+ return weapon_order_table[i].weapon_num;
+}
+
+//
+// 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
+//
+void G_BuildTiccmd (ticcmd_t* cmd, int maketic)
+{
+ int i;
+ boolean strafe;
+ boolean bstrafe;
+ int speed;
+ int tspeed;
+ int forward;
+ int side;
+
+ memset(cmd, 0, sizeof(ticcmd_t));
+
+ cmd->consistancy =
+ consistancy[consoleplayer][maketic%BACKUPTICS];
+
+ // villsa [STRIFE] look up key
+ if(gamekeydown[key_lookup])
+ cmd->buttons2 |= BT2_LOOKUP;
+
+ // villsa [STRIFE] look down key
+ if(gamekeydown[key_lookdown])
+ cmd->buttons2 |= BT2_LOOKDOWN;
+
+ // villsa [STRIFE] inventory use key
+ if(gamekeydown[key_invuse])
+ {
+ player_t* player = &players[consoleplayer];
+ if(player->numinventory > 0)
+ {
+ cmd->buttons2 |= BT2_INVUSE;
+ cmd->inventory = player->inventory[player->inventorycursor].sprite;
+ }
+ }
+
+ // villsa [STRIFE] inventory drop key
+ if(gamekeydown[key_invdrop])
+ {
+ player_t* player = &players[consoleplayer];
+ if(player->numinventory > 0)
+ {
+ cmd->buttons2 |= BT2_INVDROP;
+ cmd->inventory = player->inventory[player->inventorycursor].sprite;
+ }
+ }
+
+ // villsa [STRIFE] use medkit
+ if(gamekeydown[key_usehealth])
+ cmd->buttons2 |= BT2_HEALTH;
+
+
+
+ strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe]
+ || joybuttons[joybstrafe];
+
+ // fraggle: support the old "joyb_speed = 31" hack which
+ // allowed an autorun effect
+
+ speed = key_speed >= NUMKEYS
+ || joybspeed >= MAX_JOY_BUTTONS
+ || gamekeydown[key_speed]
+ || joybuttons[joybspeed];
+
+ forward = side = 0;
+
+ // villsa [STRIFE] running causes centerview to occur
+ if(speed)
+ cmd->buttons2 |= BT2_CENTERVIEW;
+
+ // villsa [STRIFE] disable running if low on health
+ if (players[consoleplayer].health <= 15)
+ speed = 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;
+
+ // let movement keys cancel each other out
+ if (strafe)
+ {
+ if (gamekeydown[key_right])
+ {
+ // fprintf(stderr, "strafe right\n");
+ side += sidemove[speed];
+ }
+ if (gamekeydown[key_left])
+ {
+ // fprintf(stderr, "strafe left\n");
+ 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])
+ {
+ // fprintf(stderr, "up\n");
+ forward += forwardmove[speed];
+ }
+ if (gamekeydown[key_down])
+ {
+ // fprintf(stderr, "down\n");
+ forward -= forwardmove[speed];
+ }
+
+ if (joyymove < 0)
+ forward += forwardmove[speed];
+ if (joyymove > 0)
+ forward -= forwardmove[speed];
+
+ if (gamekeydown[key_strafeleft]
+ || joybuttons[joybstrafeleft]
+ || mousebuttons[mousebstrafeleft])
+ {
+ side -= sidemove[speed];
+ }
+
+ if (gamekeydown[key_straferight]
+ || joybuttons[joybstraferight]
+ || mousebuttons[mousebstraferight])
+ {
+ side += sidemove[speed];
+ }
+
+ // buttons
+ cmd->chatchar = HU_dequeueChatChar();
+
+ // villsa [STRIFE] - add mouse button support for jump
+ if(gamekeydown[key_jump] || mousebuttons[mousebjump])
+ cmd->buttons2 |= BT2_JUMP;
+
+ // villsa [STRIFE]: Moved mousebuttons[mousebfire] to below
+ if (gamekeydown[key_fire] || joybuttons[joybfire])
+ cmd->buttons |= BT_ATTACK;
+
+ // villsa [STRIFE]
+ if(mousebuttons[mousebfire])
+ {
+ if(mouse_fire_countdown <= 0)
+ cmd->buttons |= BT_ATTACK;
+ else
+ --mouse_fire_countdown;
+ }
+
+ if (gamekeydown[key_use]
+ || joybuttons[joybuse]
+ || mousebuttons[mousebuse])
+ {
+ cmd->buttons |= BT_USE;
+ // clear double clicks if hit use button
+ dclicks = 0;
+ }
+
+ // If the previous or next weapon button is pressed, the
+ // next_weapon variable is set to change weapons when
+ // we generate a ticcmd. Choose a new weapon.
+
+ if (next_weapon != 0)
+ {
+ i = G_NextWeapon(next_weapon);
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i << BT_WEAPONSHIFT;
+ next_weapon = 0;
+ }
+ else
+ {
+ // Check weapon keys.
+
+ for (i=0; i<arrlen(weapon_keys); ++i)
+ {
+ int key = *weapon_keys[i];
+
+ if (gamekeydown[key])
+ {
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i<<BT_WEAPONSHIFT;
+ break;
+ }
+ }
+ }
+
+ // mouse
+ if (mousebuttons[mousebforward])
+ {
+ forward += forwardmove[speed];
+ }
+ if (mousebuttons[mousebbackward])
+ {
+ forward -= forwardmove[speed];
+ }
+
+ if (dclick_use)
+ {
+ // 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
+ {
+ dclicktime += ticdup;
+ if (dclicktime > 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
+ {
+ dclicktime2 += ticdup;
+ if (dclicktime2 > 20)
+ {
+ dclicks2 = 0;
+ dclickstate2 = 0;
+ }
+ }
+ }
+
+ forward += mousey;
+
+ if (strafe)
+ side += mousex*2;
+ else
+ cmd->angleturn -= mousex*0x8;
+
+ if (mousex == 0)
+ {
+ // No movement in the previous frame
+
+ testcontrols_mousespeed = 0;
+ }
+
+ 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 += forward;
+ cmd->sidemove += side;
+
+ // special buttons
+ if (sendpause)
+ {
+ sendpause = false;
+ cmd->buttons = BT_SPECIAL | BTS_PAUSE;
+ }
+
+ if (sendsave)
+ {
+ sendsave = false;
+ cmd->buttons = BT_SPECIAL | BTS_SAVEGAME | (savegameslot<<BTS_SAVESHIFT);
+ }
+
+ // low-res turning
+
+ if (lowres_turn)
+ {
+ static signed short carry = 0;
+ signed short desired_angleturn;
+
+ desired_angleturn = cmd->angleturn + carry;
+
+ // round angleturn to the nearest 256 unit boundary
+ // for recording demos with single byte values for turn
+
+ cmd->angleturn = (desired_angleturn + 128) & 0xff00;
+
+ // Carry forward the error from the reduced resolution to the
+ // next tic, so that successive small movements can accumulate.
+
+ carry = desired_angleturn - cmd->angleturn;
+ }
+}
+
+
+//
+// G_DoLoadLevel
+//
+void G_DoLoadLevel (void)
+{
+ int i;
+
+ // haleyjd 10/03/10: [STRIFE] This is not done here.
+ //skyflatnum = R_FlatNumForName(DEH_String(SKYFLATNAME));
+
+ levelstarttic = gametic; // for time calculation
+
+ if (wipegamestate == GS_LEVEL)
+ wipegamestate = -1; // force a wipe
+
+ gamestate = GS_LEVEL;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ turbodetected[i] = false;
+
+ // haleyjd 20110204 [STRIFE]: PST_REBORN if players[i].health <= 0
+ if (playeringame[i] && (players[i].playerstate == PST_DEAD || players[i].health <= 0))
+ players[i].playerstate = PST_REBORN;
+ memset (players[i].frags,0,sizeof(players[i].frags));
+ }
+
+ P_SetupLevel (gamemap, 0, gameskill);
+ displayplayer = consoleplayer; // view the guy you are playing
+ starttime = I_GetTime(); // haleyjd 20110204 [STRIFE]
+ gameaction = ga_nothing;
+ Z_CheckHeap ();
+
+ // clear cmd building stuff
+
+ memset (gamekeydown, 0, sizeof(gamekeydown));
+ joyxmove = joyymove = 0;
+ mousex = mousey = 0;
+ sendpause = sendsave = paused = false;
+ memset (mousebuttons, 0, sizeof(mousebuttons));
+ memset (joybuttons, 0, sizeof(joybuttons));
+
+ if (testcontrols)
+ {
+ players[consoleplayer].message = "Press escape to quit.";
+ }
+
+ P_DialogLoad(); // villsa [STRIFE]
+}
+
+static void SetJoyButtons(unsigned int buttons_mask)
+{
+ int i;
+
+ for (i=0; i<MAX_JOY_BUTTONS; ++i)
+ {
+ int button_on = (buttons_mask & (1 << i)) != 0;
+
+ // Detect button press:
+
+ if (!joybuttons[i] && button_on)
+ {
+ // Weapon cycling:
+
+ if (i == joybprevweapon)
+ {
+ next_weapon = -1;
+ }
+ else if (i == joybnextweapon)
+ {
+ next_weapon = 1;
+ }
+ }
+
+ joybuttons[i] = button_on;
+ }
+}
+
+static void SetMouseButtons(unsigned int buttons_mask)
+{
+ int i;
+
+ for (i=0; i<MAX_MOUSE_BUTTONS; ++i)
+ {
+ unsigned int button_on = (buttons_mask & (1 << i)) != 0;
+
+ // Detect button press:
+
+ if (!mousebuttons[i] && button_on)
+ {
+ if (i == mousebprevweapon)
+ {
+ next_weapon = -1;
+ }
+ else if (i == mousebnextweapon)
+ {
+ next_weapon = 1;
+ }
+ }
+
+ mousebuttons[i] = button_on;
+ }
+}
+
+//
+// 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
+ if (gamestate == GS_LEVEL && ev->type == ev_keydown
+ && ev->data1 == key_spy && (singledemo || !gameskill) ) // [STRIFE]: o_O
+ {
+ // spy mode
+ do
+ {
+ displayplayer++;
+ if (displayplayer == MAXPLAYERS)
+ displayplayer = 0;
+ } while (!playeringame[displayplayer] && displayplayer != consoleplayer);
+ return true;
+ }
+
+ // any other key pops up menu if in demos
+ if (gameaction == ga_nothing && !singledemo &&
+ (demoplayback || gamestate == GS_DEMOSCREEN)
+ )
+ {
+ if (ev->type == ev_keydown ||
+ (ev->type == ev_mouse && ev->data1) ||
+ (ev->type == ev_joystick && ev->data1) )
+ {
+ if(devparm && ev->data1 == 'g')
+ D_PageTicker(); // [STRIFE]: wat? o_O
+ else
+ M_StartControlPanel ();
+ return true;
+ }
+ return false;
+ }
+
+ if (gamestate == GS_LEVEL)
+ {
+#if 0
+ if (devparm && ev->type == ev_keydown && ev->data1 == ';')
+ {
+ G_DeathMatchSpawnPlayer (0);
+ return true;
+ }
+#endif
+ if (HU_Responder (ev))
+ return true; // chat ate the event
+ if (ST_Responder (ev))
+ return true; // status window ate it
+ if (AM_Responder (ev))
+ return true; // automap ate it
+ }
+
+ if (gamestate == GS_FINALE)
+ {
+ if (F_Responder (ev))
+ return true; // finale ate the event
+ }
+
+ if (testcontrols && ev->type == ev_mouse)
+ {
+ // If we are invoked by setup to test the controls, save the
+ // mouse speed so that we can display it on-screen.
+ // Perform a low pass filter on this so that the thermometer
+ // appears to move smoothly.
+
+ testcontrols_mousespeed = abs(ev->data2);
+ }
+
+ // If the next/previous weapon keys are pressed, set the next_weapon
+ // variable to change weapons when the next ticcmd is generated.
+
+ if (ev->type == ev_keydown && ev->data1 == key_prevweapon)
+ {
+ next_weapon = -1;
+ }
+ else if (ev->type == ev_keydown && ev->data1 == key_nextweapon)
+ {
+ next_weapon = 1;
+ }
+
+ switch (ev->type)
+ {
+ case ev_keydown:
+ if (ev->data1 == key_pause)
+ {
+ sendpause = true;
+ }
+ else 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:
+ SetMouseButtons(ev->data1);
+ mousex = ev->data2*(mouseSensitivity+5)/10;
+ mousey = ev->data3*(mouseSensitivity+5)/10;
+ return true; // eat events
+
+ case ev_joystick:
+ SetJoyButtons(ev->data1);
+ joyxmove = ev->data2;
+ joyymove = ev->data3;
+ return true; // eat events
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+//
+// G_Ticker
+// Make ticcmd_ts for the players.
+//
+void G_Ticker (void)
+{
+ int i;
+ int buf;
+ ticcmd_t* cmd;
+
+ // do player reborns if needed
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ if (playeringame[i] && players[i].playerstate == PST_REBORN)
+ G_DoReborn (i);
+
+ // do things to change the game state
+ while (gameaction != ga_nothing)
+ {
+ switch (gameaction)
+ {
+ case ga_loadlevel:
+ G_DoLoadLevel ();
+ break;
+ case ga_newgame:
+ G_DoNewGame ();
+ break;
+ case ga_loadgame:
+ G_DoLoadGame(true);
+ M_SaveMoveHereToMap(); // [STRIFE]
+ M_ReadMisObj();
+ break;
+ case ga_savegame:
+ M_SaveMoveMapToHere(); // [STRIFE]
+ M_SaveMisObj(savepath);
+ G_DoSaveGame(savepath);
+ 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_screenshot:
+ V_ScreenShot("STRIFE%02i.pcx"); // [STRIFE] file name, message
+ players[consoleplayer].message = DEH_String("STRIFE by Rogue entertainment");
+ gameaction = ga_nothing;
+ break;
+ case ga_nothing:
+ break;
+ }
+ }
+
+ // get commands, check consistancy,
+ // and build new consistancy check
+ buf = (gametic/ticdup)%BACKUPTICS;
+
+ // STRIFE-TODO: pnameprefixes bullcrap
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ cmd = &players[i].cmd;
+
+ memcpy (cmd, &netcmds[i], sizeof(ticcmd_t));
+
+ if (demoplayback)
+ G_ReadDemoTiccmd (cmd);
+ if (demorecording)
+ G_WriteDemoTiccmd (cmd);
+
+ // check for turbo cheats
+
+ // check ~ 4 seconds whether to display the turbo message.
+ // store if the turbo threshold was exceeded in any tics
+ // over the past 4 seconds. offset the checking period
+ // for each player so messages are not displayed at the
+ // same time.
+
+ if (cmd->forwardmove > TURBOTHRESHOLD)
+ {
+ turbodetected[i] = true;
+ }
+
+ if ((gametic & 31) == 0
+ && ((gametic >> 5) % MAXPLAYERS) == i
+ && turbodetected[i])
+ {
+ static char turbomessage[80];
+ extern char *player_names[4];
+ sprintf (turbomessage, "%s is turbo!",player_names[i]);
+ players[consoleplayer].message = turbomessage;
+ turbodetected[i] = false;
+ }
+
+ if (netgame && !netdemo && !(gametic%ticdup) )
+ {
+ if (gametic > BACKUPTICS
+ && consistancy[i][buf] != cmd->consistancy)
+ {
+ I_Error ("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] = rndindex;
+ }
+ }
+ }
+
+ // 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 (!character_name[0]) // [STRIFE]
+ strcpy (character_name, "NET GAME");
+ savegameslot =
+ (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT;
+ gameaction = ga_savegame;
+ break;
+ }
+ }
+ }
+ }
+
+ // Have we just finished displaying an intermission screen?
+ // haleyjd 08/23/10: [STRIFE] No intermission.
+ /*
+ if (oldgamestate == GS_INTERMISSION && gamestate != GS_INTERMISSION)
+ {
+ WI_End();
+ }
+ */
+
+ oldgamestate = gamestate;
+
+ // do main actions
+ switch (gamestate)
+ {
+ case GS_LEVEL:
+ P_Ticker ();
+ ST_Ticker ();
+ AM_Ticker ();
+ HU_Ticker ();
+ break;
+
+ // haleyjd 08/23/10: [STRIFE] No intermission.
+ /*
+ case GS_INTERMISSION:
+ WI_Ticker ();
+ break;
+ */
+ case GS_UNKNOWN: // STRIFE-TODO: What is this? is it ever used??
+ F_WaitTicker();
+ break;
+
+ case GS_FINALE:
+ F_Ticker ();
+ break;
+
+ case GS_DEMOSCREEN:
+ D_PageTicker ();
+ break;
+ }
+}
+
+
+//
+// PLAYER STRUCTURE FUNCTIONS
+// also see P_SpawnPlayer in P_Things
+//
+
+//
+// G_InitPlayer
+// Called at the start.
+// Called by the game initialization functions.
+//
+// [STRIFE] No such function.
+/*
+void G_InitPlayer (int player)
+{
+ player_t* p;
+
+ // set up the saved info
+ p = &players[player];
+
+ // clear everything else to defaults
+ G_PlayerReborn (player);
+
+}
+*/
+
+
+//
+// G_PlayerFinishLevel
+// Can when a player completes a level.
+//
+// [STRIFE] No such function. The equivalent to this logic was moved into
+// G_DoCompleted.
+/*
+void G_PlayerFinishLevel (int player)
+{
+ player_t* p;
+
+ 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;
+}
+*/
+
+//
+// G_PlayerReborn
+// Called after a player dies
+// almost everything is cleared and initialized
+//
+// [STRIFE] Small changes for allegiance, inventory, health auto-use, and
+// mission objective.
+//
+void G_PlayerReborn (int player)
+{
+ player_t* p;
+ int i;
+ int frags[MAXPLAYERS];
+ int killcount;
+ int allegiance;
+
+ killcount = players[player].killcount;
+ allegiance = players[player].allegiance; // [STRIFE]
+
+ memcpy(frags,players[player].frags,sizeof(frags));
+
+ p = &players[player];
+ memset (p, 0, sizeof(*p));
+
+ memcpy(p->frags, frags, sizeof(p->frags));
+
+ p->usedown = true; // don't do anything immediately
+ p->attackdown = true;
+ p->inventorydown = true; // villsa [STRIFE]
+ p->playerstate = PST_LIVE;
+ p->health = deh_initial_health; // Use dehacked value
+ p->readyweapon = wp_fist; // villsa [STRIFE] default to fists
+ p->pendingweapon = wp_fist; // villsa [STRIFE] default to fists
+ p->weaponowned[wp_fist] = true; // villsa [STRIFE] default to fists
+ p->cheats |= CF_AUTOHEALTH; // villsa [STRIFE]
+ p->killcount = killcount;
+ p->allegiance = allegiance; // villsa [STRIFE]
+ p->centerview = true; // villsa [STRIFE]
+
+ for(i = 0; i < NUMAMMO; i++)
+ p->maxammo[i] = maxammo[i];
+
+ // [STRIFE] clear inventory
+ for(i = 0; i < 32; i++)
+ p->inventory[i].type = NUMMOBJTYPES;
+
+ // villsa [STRIFE]: Default objective
+ strncpy(mission_objective, DEH_String("Find help"), OBJECTIVE_LEN);
+}
+
+//
+// G_CheckSpot
+// Returns false if the player cannot be respawned
+// at the given mapthing_t spot
+// because something is occupying it
+//
+// [STRIFE] Changed to eliminate body queue and an odd error message was added.
+//
+void P_SpawnPlayer (mapthing_t* mthing);
+
+boolean
+G_CheckSpot
+( int playernum,
+ mapthing_t* mthing )
+{
+ fixed_t x;
+ fixed_t y;
+ subsector_t* ss;
+ unsigned an;
+ mobj_t* mo;
+ int i;
+
+ if (!players[playernum].mo)
+ {
+ // [STRIFE] weird error message added here:
+ if(leveltime > 0)
+ players[playernum].message = DEH_String("you didn't have a body!");
+
+ // 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;
+
+ if (!P_CheckPosition (players[playernum].mo, x, y) )
+ return false;
+
+ // flush an old corpse if needed
+ // [STRIFE] player corpses remove themselves after a short time, so
+ // evidently this wasn't needed.
+ /*
+ if (bodyqueslot >= BODYQUESIZE)
+ P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]);
+ bodyque[bodyqueslot%BODYQUESIZE] = players[playernum].mo;
+ bodyqueslot++;
+ */
+
+ // spawn a teleport fog
+ ss = R_PointInSubsector (x,y);
+ an = ( ANG45 * (((unsigned int) mthing->angle)/45) ) >> ANGLETOFINESHIFT;
+
+ mo = P_SpawnMobj (x+20*finecosine[an], y+20*finesine[an]
+ , 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
+//
+// [STRIFE] Verified unmodified
+//
+void G_DeathMatchSpawnPlayer (int playernum)
+{
+ int i,j;
+ int selections;
+
+ selections = deathmatch_p - deathmatchstarts;
+ if (selections < 4)
+ I_Error ("Only %i deathmatch spots, 4 required", selections);
+
+ for (j=0 ; j<20 ; j++)
+ {
+ i = P_Random() % 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_LoadPath
+//
+// haleyjd 10/03/10: [STRIFE] New function
+// Sets loadpath based on the map and "savepathtemp"
+//
+void G_LoadPath(int map)
+{
+ char mapbuf[33];
+
+ memset(mapbuf, 0, sizeof(mapbuf));
+ sprintf(mapbuf, "%d", map);
+
+ // haleyjd: free if already set, and use M_SafeFilePath
+ if(loadpath)
+ Z_Free(loadpath);
+ loadpath = M_SafeFilePath(savepathtemp, mapbuf);
+}
+
+//
+// G_DoReborn
+//
+void G_DoReborn (int playernum)
+{
+ int i;
+
+ if (!netgame)
+ {
+ // reload the level from scratch
+ // [STRIFE] Reborn level load
+ G_LoadPath(gamemap);
+ gameaction = ga_loadgame;
+ }
+ else
+ {
+ // respawn at the start
+
+ // first dissasociate the corpse
+ // [STRIFE] Checks for NULL first
+ if(players[playernum].mo)
+ 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]);
+ }
+}
+
+//
+// G_ScreenShot
+//
+// [STRIFE] Verified unmodified
+//
+void G_ScreenShot (void)
+{
+ gameaction = ga_screenshot;
+}
+
+// haleyjd 08/23/2010: [STRIFE] Removed par times.
+
+//
+// G_DoCompleted
+//
+//boolean secretexit;
+extern char* pagename;
+
+//
+// G_RiftExitLevel
+//
+// haleyjd 08/24/10: [STRIFE] New function
+// * Called from some exit linedefs to exit to a specific riftspot in the
+// given destination map.
+//
+void G_RiftExitLevel(int map, int spot, angle_t angle)
+{
+ gameaction = ga_completed;
+
+ // special handling for post-Sigil map changes
+ if(players[0].weaponowned[wp_sigil])
+ {
+ if(map == 3) // Front Base -> Abandoned Front Base
+ map = 30;
+ if(map == 7) // Castle -> New Front Base
+ map = 10;
+ }
+
+ // no rifting in deathmatch games
+ if(deathmatch)
+ spot = 0;
+
+ riftangle = angle;
+ riftdest = spot;
+ destmap = map;
+}
+
+//
+// G_Exit2
+//
+// haleyjd 10/03/10: [STRIFE] New function.
+// No xrefs to this, doesn't seem to be used. Could have gotten inlined
+// somewhere but I haven't seen it.
+//
+void G_Exit2(int dest, angle_t angle)
+{
+ riftdest = dest;
+ gameaction = ga_completed;
+ riftangle = angle;
+ destmap = gamemap;
+}
+
+//
+// G_ExitLevel
+//
+// haleyjd 08/24/10: [STRIFE]:
+// * Default to next map in numeric order; init destmap and riftdest.
+//
+void G_ExitLevel (int dest)
+{
+ if(dest == 0)
+ dest = gamemap + 1;
+ destmap = dest;
+ riftdest = 0;
+ gameaction = ga_completed;
+}
+
+/*
+// haleyjd 08/23/2010: [STRIFE] No secret exits in Strife.
+// Here's for the german edition.
+void G_SecretExitLevel (void)
+{
+ // IF NO WOLF3D LEVELS, NO SECRET EXIT!
+ if ( (gamemode == commercial)
+ && (W_CheckNumForName("map31")<0))
+ secretexit = false;
+ else
+ secretexit = true;
+ gameaction = ga_completed;
+}
+*/
+
+//
+// G_StartFinale
+//
+// haleyjd 09/21/10: [STRIFE] New function.
+// This replaced G_SecretExitLevel in Strife. I don't know that it's actually
+// used anywhere in the game, but it *is* usable in mods via linetype 124,
+// W1 Start Finale.
+//
+void G_StartFinale(void)
+{
+ gameaction = ga_victory;
+}
+
+//
+// G_DoCompleted
+//
+// haleyjd 08/23/10: [STRIFE]:
+// * Removed G_PlayerFinishLevel and just sets some powerup states.
+// * Removed Chex, as not relevant to Strife.
+// * Removed DOOM level transfer logic
+// * Removed intermission code.
+// * Added setting gameaction to ga_worlddone.
+//
+void G_DoCompleted (void)
+{
+ int i;
+
+ // deal with powerup states
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ if(playeringame[i])
+ {
+ // [STRIFE] restore pw_allmap power from mapstate cache
+ if(destmap < 40)
+ players[i].powers[pw_allmap] = players[i].mapstate[destmap];
+
+ // Shadowarmor doesn't persist between maps in netgames
+ if(netgame)
+ players[i].powers[pw_invisibility] = 0;
+ }
+ }
+
+ stonecold = false; // villsa [STRIFE]
+
+ if (automapactive)
+ AM_Stop ();
+
+ // [STRIFE] HUB SAVE
+ if(!deathmatch)
+ G_DoSaveGame(savepathtemp);
+
+ gameaction = ga_worlddone;
+}
+
+
+// haleyjd 08/24/10: [STRIFE] No secret exits.
+/*
+//
+// 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;
+ }
+ }
+}
+*/
+
+//
+// G_RiftPlayer
+//
+// haleyjd 08/24/10: [STRIFE] New function
+// Teleports the player to the appropriate rift spot.
+//
+void G_RiftPlayer(void)
+{
+ if(riftdest)
+ {
+ P_TeleportMove(players[0].mo,
+ riftSpots[riftdest - 1].x << FRACBITS,
+ riftSpots[riftdest - 1].y << FRACBITS);
+ players[0].mo->angle = riftangle;
+ players[0].mo->health = players[0].health;
+ }
+}
+
+//
+// G_RiftCheat
+//
+// haleyjd 08/24/10: [STRIFE] New function
+// Called from the cheat code to jump to a rift spot.
+//
+boolean G_RiftCheat(int riftSpotNum)
+{
+ return P_TeleportMove(players[0].mo,
+ riftSpots[riftSpotNum - 1].x << FRACBITS,
+ riftSpots[riftSpotNum - 1].y << FRACBITS);
+}
+
+//
+// G_DoWorldDone
+//
+// haleyjd 08/24/10: [STRIFE] Added destmap -> gamemap set.
+//
+void G_DoWorldDone (void)
+{
+ int temp_leveltime = leveltime;
+ boolean temp_shadow = false;
+ boolean temp_mvis = false;
+
+ gamestate = GS_LEVEL;
+ gamemap = destmap;
+
+ // [STRIFE] HUB LOAD
+ G_LoadPath(destmap);
+ if (!deathmatch)
+ {
+ // Remember Shadowarmor across hub loads
+ if(players[0].mo->flags & MF_SHADOW)
+ temp_shadow = true;
+ if(players[0].mo->flags & MF_MVIS)
+ temp_mvis = true;
+ }
+ G_DoLoadGame(false);
+
+ // [STRIFE] leveltime carries over between maps
+ leveltime = temp_leveltime;
+
+ if(!deathmatch)
+ {
+ // [STRIFE]: transfer saved powerups
+ players[0].mo->flags &= ~(MF_SHADOW|MF_MVIS);
+ if(temp_shadow)
+ players[0].mo->flags |= MF_SHADOW;
+ if(temp_mvis)
+ players[0].mo->flags |= MF_MVIS;
+
+ // [STRIFE] HUB SAVE
+ G_RiftPlayer();
+ G_DoSaveGame(savepathtemp);
+ M_SaveMisObj(savepathtemp);
+ }
+
+ gameaction = ga_nothing;
+ viewactive = true;
+}
+
+//
+// G_DoWorldDone2
+//
+// haleyjd 10/03/10: [STRIFE] New function. No xrefs; unused.
+//
+void G_DoWorldDone2(void)
+{
+ gamestate = GS_LEVEL;
+ gameaction = ga_nothing;
+ viewactive = true;
+}
+
+//
+// G_ReadCurrent
+//
+// haleyjd 10/03/10: [STRIFE] New function.
+// Reads the "CURRENT" file from the given path and then sets it to
+// gamemap.
+//
+void G_ReadCurrent(const char *path)
+{
+ char *temppath = NULL;
+ byte *buffer = NULL;
+
+ temppath = M_SafeFilePath(path, "\\current");
+
+ if(M_ReadFile(temppath, &buffer) <= 0)
+ gameaction = ga_newgame;
+ else
+ {
+ // haleyjd 20110211: do endian-correct read
+ gamemap = (((int)buffer[0]) |
+ ((int)buffer[1] << 8) |
+ ((int)buffer[2] << 16) |
+ ((int)buffer[3] << 24));
+ gameaction = ga_loadgame;
+ Z_Free(buffer);
+ }
+
+ Z_Free(temppath);
+
+ G_LoadPath(gamemap);
+}
+
+//
+// G_InitFromSavegame
+// Can be called by the startup code or the menu task.
+//
+extern boolean setsizeneeded;
+void R_ExecuteSetViewSize (void);
+
+char savename[256];
+
+// [STRIFE]: No such function, at least in v1.2
+// STRIFE-TODO: Does this come back in v1.31?
+/*
+void G_LoadGame (char* name)
+{
+ strcpy (savename, name);
+ gameaction = ga_loadgame;
+}
+*/
+
+// haleyjd 09/28/10: [STRIFE] VERSIONSIZE == 8
+#define VERSIONSIZE 8
+
+void G_DoLoadGame (boolean userload)
+{
+ int savedleveltime;
+
+ gameaction = ga_nothing;
+
+ save_stream = fopen(loadpath, "rb");
+
+ // [STRIFE] If the file does not exist, G_DoLoadLevel is called.
+ if (save_stream == NULL)
+ {
+ G_DoLoadLevel();
+ return;
+ }
+
+ savegame_error = false;
+
+ if (!P_ReadSaveGameHeader())
+ {
+ fclose(save_stream);
+ return;
+ }
+
+ // haleyjd: A comment would be good here, fraggle...
+ // Evidently this is a Choco-ism, necessitated by reading the savegame
+ // header *before* calling G_DoLoadLevel.
+ savedleveltime = leveltime;
+
+ // load a base level
+
+ // STRIFE-TODO: ????
+ if(userload)
+ G_InitNew(gameskill, gamemap);
+ else
+ G_DoLoadLevel();
+
+ leveltime = savedleveltime;
+
+ // dearchive all the modifications
+ // [STRIFE] some portions of player_t are not overwritten when loading
+ // between hub levels
+ P_UnArchivePlayers (userload);
+ P_UnArchiveWorld ();
+ P_UnArchiveThinkers ();
+ P_UnArchiveSpecials ();
+
+ if (!P_ReadSaveGameEOF())
+ I_Error ("Bad savegame");
+
+ fclose(save_stream);
+
+ if (setsizeneeded)
+ R_ExecuteSetViewSize ();
+
+ // draw the pattern into the back screen
+ R_FillBackScreen ();
+}
+
+//
+// G_WriteSaveName
+//
+// haleyjd 2010103: [STRIFE] New function
+//
+// Writes the character name to the NAME file.
+//
+boolean G_WriteSaveName(int slot, const char *charname)
+{
+ //char savedir[16];
+ char *tmpname;
+ boolean retval;
+
+ savegameslot = slot;
+
+ // haleyjd: removed special -cdrom treatment, as I believe it is taken
+ // care of automatically via using Choco's savegamedir setting.
+
+ // haleyjd: free previous path, if any, and allocate new one using
+ // M_SafeFilePath routine, which isn't limited to 128 characters.
+ if(savepathtemp)
+ Z_Free(savepathtemp);
+ savepathtemp = M_SafeFilePath(savegamedir, "strfsav6.ssg");
+
+ // haleyjd: as above.
+ if(savepath)
+ Z_Free(savepath);
+ savepath = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(savegameslot, ""));
+
+ // haleyjd: memset full character_name for safety
+ memset(character_name, 0, CHARACTER_NAME_LEN);
+ strcpy(character_name, charname);
+
+ // haleyjd: use M_SafeFilePath
+ tmpname = M_SafeFilePath(savepathtemp, "name");
+
+ // Write the "name" file under the directory
+ retval = M_WriteFile(tmpname, character_name, 32);
+
+ Z_Free(tmpname);
+
+ return retval;
+}
+
+//
+// G_SaveGame
+// Called by the menu task.
+// Description is a 24 byte text string
+//
+// [STRIFE] No such function, at least in v1.2
+// STRIFE-TODO: Does this make a comeback in v1.31?
+/*
+void
+G_SaveGame
+( int slot,
+ char* description )
+{
+ savegameslot = slot;
+ strcpy (savedescription, description);
+ sendsave = true;
+}
+*/
+
+void G_DoSaveGame (char *path)
+{
+ char *current_path;
+ char *savegame_file;
+ char *temp_savegame_file;
+ byte gamemapbytes[4];
+ char gamemapstr[33];
+
+ temp_savegame_file = P_TempSaveGameFile();
+
+ // [STRIFE] custom save file path logic
+ memset(gamemapstr, 0, sizeof(gamemapstr));
+ sprintf(gamemapstr, "%d", gamemap);
+ savegame_file = M_SafeFilePath(path, gamemapstr);
+
+ // [STRIFE] write the "current" file, which tells which hub map
+ // the save slot is currently on.
+ current_path = M_SafeFilePath(path, "current");
+ // haleyjd: endian-agnostic IO
+ gamemapbytes[0] = (byte)( gamemap & 0xff);
+ gamemapbytes[1] = (byte)((gamemap >> 8) & 0xff);
+ gamemapbytes[2] = (byte)((gamemap >> 16) & 0xff);
+ gamemapbytes[3] = (byte)((gamemap >> 24) & 0xff);
+ M_WriteFile(current_path, gamemapbytes, 4);
+ Z_Free(current_path);
+
+ // Open the savegame file for writing. We write to a temporary file
+ // and then rename it at the end if it was successfully written.
+ // This prevents an existing savegame from being overwritten by
+ // a corrupted one, or if a savegame buffer overrun occurs.
+
+ save_stream = fopen(temp_savegame_file, "wb");
+
+ if (save_stream == NULL)
+ {
+ return;
+ }
+
+ savegame_error = false;
+
+ P_WriteSaveGameHeader(savedescription);
+
+ P_ArchivePlayers ();
+ P_ArchiveWorld ();
+ P_ArchiveThinkers ();
+ P_ArchiveSpecials ();
+
+ P_WriteSaveGameEOF();
+
+ // Enforce the same savegame size limit as in Vanilla Doom,
+ // except if the vanilla_savegame_limit setting is turned off.
+ // [STRIFE]: Verified subject to same limit.
+
+ if (vanilla_savegame_limit && ftell(save_stream) > SAVEGAMESIZE)
+ {
+ I_Error ("Savegame buffer overrun");
+ }
+
+ // Finish up, close the savegame file.
+
+ fclose(save_stream);
+
+ // Now rename the temporary savegame file to the actual savegame
+ // file, overwriting the old savegame if there was one there.
+
+ remove(savegame_file);
+ rename(temp_savegame_file, savegame_file);
+
+ // haleyjd: free the savegame_file path
+ Z_Free(savegame_file);
+
+ gameaction = ga_nothing;
+ //strcpy(savedescription, "");
+
+ // [STRIFE]: custom message logic
+ if(!strcmp(path, savepath))
+ {
+ sprintf(savename, "%s saved.", character_name);
+ players[consoleplayer].message = savename;
+ }
+
+ // draw the pattern into the back screen
+ R_FillBackScreen ();
+}
+
+
+//
+skill_t d_skill;
+//int d_episode; [STRIFE] No such thing as episodes in Strife
+int d_map;
+
+//
+// G_DeferedInitNew
+//
+// Can be called by the startup code or the menu task,
+// consoleplayer, displayplayer, playeringame[] should be set.
+//
+// haleyjd 09/22/10: [STRIFE] Removed episode parameter
+//
+void G_DeferedInitNew(skill_t skill, int map)
+{
+ d_skill = skill;
+ d_map = map;
+ gameaction = ga_newgame;
+}
+
+//
+// G_DoNewGame
+//
+// [STRIFE] Code added to turn off the stonecold effect.
+// Someone also removed the nomonsters reset...
+//
+void G_DoNewGame (void)
+{
+ demoplayback = false;
+ netdemo = false;
+ netgame = false;
+ deathmatch = false;
+ playeringame[1] = playeringame[2] = playeringame[3] = 0;
+ respawnparm = false;
+ fastparm = false;
+ stonecold = false; // villsa [STRIFE]
+ //nomonsters = false; [STRIFE] not set here!?!
+ consoleplayer = 0;
+ G_InitNew (d_skill, d_map);
+ gameaction = ga_nothing;
+}
+
+//
+// G_InitNew
+//
+// haleyjd 08/24/10: [STRIFE]:
+// * Added riftdest initialization
+// * Removed episode parameter
+//
+void
+G_InitNew
+( skill_t skill,
+ int map )
+{
+ char *skytexturename;
+ int i;
+
+ if (paused)
+ {
+ paused = false;
+ S_ResumeSound ();
+ }
+
+ if (skill > sk_nightmare)
+ skill = sk_nightmare;
+
+ // [STRIFE] Removed episode nonsense and gamemap clipping
+
+ M_ClearRandom ();
+
+ if (skill == sk_nightmare || respawnparm )
+ respawnmonsters = true;
+ else
+ respawnmonsters = false;
+
+ // [STRIFE] Strife skill level mobjinfo/states tweaking
+ // BUG: None of this code runs properly when loading save games, so
+ // basically it's impossible to play any skill level properly unless
+ // you never quit and reload from the command line.
+ if(!skill && gameskill)
+ {
+ // Setting to Baby skill... make things easier.
+
+ // Acolytes walk, attack, and feel pain slower
+ for(i = S_AGRD_13; i <= S_AGRD_23; i++)
+ states[i].tics *= 2;
+
+ // Reavers attack slower
+ for(i = S_ROB1_10; i <= S_ROB1_15; i++)
+ states[i].tics *= 2;
+
+ // Turrets attack slower
+ for(i = S_TURT_02; i <= S_TURT_03; i++)
+ states[i].tics *= 2;
+
+ // Crusaders attack and feel pain slower
+ for(i = S_ROB2_09; i <= S_ROB2_19; i++)
+ states[i].tics *= 2;
+
+ // Stalkers think, walk, and attack slower
+ for(i = S_SPID_03; i <= S_SPID_10; i++)
+ states[i].tics *= 2;
+
+ // The Bishop's homing missiles are faster (what?? BUG?)
+ mobjinfo[MT_SEEKMISSILE].speed *= 2;
+ }
+ if(skill && !gameskill)
+ {
+ // Setting a higher skill when previously on baby... make things normal
+
+ // Acolytes
+ for(i = S_AGRD_13; i <= S_AGRD_23; i++)
+ states[i].tics >>= 1;
+
+ // Reavers
+ for(i = S_ROB1_10; i <= S_ROB1_15; i++)
+ states[i].tics >>= 1;
+
+ // Turrets
+ for(i = S_TURT_02; i <= S_TURT_03; i++)
+ states[i].tics >>= 1;
+
+ // Crusaders
+ for(i = S_ROB2_09; i <= S_ROB2_19; i++)
+ states[i].tics >>= 1;
+
+ // Stalkers
+ for(i = S_SPID_03; i <= S_SPID_10; i++)
+ states[i].tics >>= 1;
+
+ // The Bishop's homing missiles - again, seemingly backward.
+ mobjinfo[MT_SEEKMISSILE].speed >>= 1;
+ }
+ if(fastparm || (skill == sk_nightmare && skill != gameskill))
+ {
+ // BLOODBATH! Make some things super-aggressive.
+
+ // Acolytes walk, attack, and feel pain twice as fast
+ // (This makes just getting out of the first room almost impossible)
+ for(i = S_AGRD_13; i <= S_AGRD_23; i++)
+ states[i].tics >>= 1;
+
+ // Bishop's homing missiles again get SLOWER and not faster o_O
+ mobjinfo[MT_SEEKMISSILE].speed >>= 1;
+ }
+ else if(skill != sk_nightmare && gameskill == sk_nightmare)
+ {
+ // Setting back to an ordinary skill after being on Bloodbath?
+ // Put stuff back to normal.
+
+ // Acolytes
+ for(i = S_AGRD_13; i <= S_AGRD_23; i++)
+ states[i].tics *= 2;
+
+ // Bishop's homing missiles
+ mobjinfo[MT_SEEKMISSILE].speed *= 2;
+ }
+
+ // 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;
+ demoplayback = false;
+ automapactive = false;
+ viewactive = true;
+ //gameepisode = episode; [STRIFE] no episodes
+ gamemap = map;
+ gameskill = skill;
+ riftdest = 0; // haleyjd 08/24/10: [STRIFE] init riftdest to zero on new game
+
+ // Set the sky to use.
+ //
+ // Note: This IS broken, but it is how Vanilla Doom behaves.
+ // See http://doom.wikia.com/wiki/Sky_never_changes_in_Doom_II.
+ //
+ // Because we set the sky here at the start of a game, not at the
+ // start of a level, the sky texture never changes unless we
+ // restore from a saved game. This was fixed before the Doom
+ // source release, but this IS the way Vanilla DOS Doom behaves.
+
+ // [STRIFE] Strife skies (of which there are but two)
+ if(gamemap >= 9 && gamemap < 32)
+ skytexturename = "skymnt01";
+ else
+ skytexturename = "skymnt02";
+
+ skytexturename = DEH_String(skytexturename);
+
+ skytexture = R_TextureNumForName(skytexturename);
+
+ // [STRIFE] HUBS
+ G_LoadPath(gamemap);
+ G_DoLoadLevel();
+}
+
+
+//
+// DEMO RECORDING
+//
+#define DEMOMARKER 0x80
+
+//
+// G_ReadDemoTiccmd
+//
+// [STRIFE] Modified for Strife ticcmd_t
+//
+void G_ReadDemoTiccmd (ticcmd_t* cmd)
+{
+ if (*demo_p == DEMOMARKER)
+ {
+ // end of demo data stream
+ G_CheckDemoStatus ();
+ return;
+ }
+ cmd->forwardmove = ((signed char)*demo_p++);
+ cmd->sidemove = ((signed char)*demo_p++);
+ cmd->angleturn = ((unsigned char) *demo_p++)<<8;
+ cmd->buttons = (unsigned char)*demo_p++;
+ cmd->buttons2 = (unsigned char)*demo_p++; // [STRIFE]
+ cmd->inventory = (int)*demo_p++; // [STRIFE]
+}
+
+// Increase the size of the demo buffer to allow unlimited demos
+
+static void IncreaseDemoBuffer(void)
+{
+ int current_length;
+ byte *new_demobuffer;
+ byte *new_demop;
+ int new_length;
+
+ // Find the current size
+
+ current_length = demoend - demobuffer;
+
+ // Generate a new buffer twice the size
+ new_length = current_length * 2;
+
+ new_demobuffer = Z_Malloc(new_length, PU_STATIC, 0);
+ new_demop = new_demobuffer + (demo_p - demobuffer);
+
+ // Copy over the old data
+
+ memcpy(new_demobuffer, demobuffer, current_length);
+
+ // Free the old buffer and point the demo pointers at the new buffer.
+
+ Z_Free(demobuffer);
+
+ demobuffer = new_demobuffer;
+ demo_p = new_demop;
+ demoend = demobuffer + new_length;
+}
+
+//
+// G_WriteDemoTiccmd
+//
+// [STRIFE] Modified for Strife ticcmd_t.
+//
+void G_WriteDemoTiccmd (ticcmd_t* cmd)
+{
+ byte *demo_start;
+
+ if (gamekeydown[key_demo_quit]) // press q to end demo recording
+ G_CheckDemoStatus ();
+
+ demo_start = demo_p;
+
+ *demo_p++ = cmd->forwardmove;
+ *demo_p++ = cmd->sidemove;
+ *demo_p++ = cmd->angleturn >> 8;
+ *demo_p++ = cmd->buttons;
+ *demo_p++ = cmd->buttons2; // [STRIFE]
+ *demo_p++ = (byte)(cmd->inventory & 0xff); // [STRIFE]
+
+ // reset demo pointer back
+ demo_p = demo_start;
+
+ if (demo_p > demoend - 16)
+ {
+ if (vanilla_demo_limit)
+ {
+ // no more space
+ G_CheckDemoStatus ();
+ return;
+ }
+ else
+ {
+ // Vanilla demo limit disabled: unlimited
+ // demo lengths!
+
+ IncreaseDemoBuffer();
+ }
+ }
+
+ G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same
+}
+
+
+
+//
+// G_RecordDemo
+//
+// [STRIFE] Verified unmodified
+//
+void G_RecordDemo (char* name)
+{
+ int i;
+ int maxsize;
+
+ usergame = false;
+ demoname = Z_Malloc(strlen(name) + 5, PU_STATIC, NULL);
+ sprintf(demoname, "%s.lmp", name);
+ maxsize = 0x20000;
+
+ //!
+ // @arg <size>
+ // @category demo
+ // @vanilla
+ //
+ // Specify the demo buffer size (KiB)
+ //
+
+ i = M_CheckParmWithArgs("-maxdemo", 1);
+ if (i)
+ maxsize = atoi(myargv[i+1])*1024;
+ demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL);
+ demoend = demobuffer + maxsize;
+
+ demorecording = true;
+}
+
+
+void G_BeginRecording (void)
+{
+ int i;
+
+ //
+ // @category demo
+ //
+ // Record a high resolution "Doom 1.91" demo.
+ //
+
+ // STRIFE-TODO: if somebody makes a "Strife Plus", we could add this.
+ /*
+ longtics = M_CheckParm("-longtics") != 0;
+ */
+ longtics = false;
+
+ // If not recording a longtics demo, record in low res
+ lowres_turn = !longtics;
+
+ demo_p = demobuffer;
+
+ // Save the right version code for this demo
+ *demo_p++ = STRIFE_VERSION;
+
+ *demo_p++ = gameskill;
+ //*demo_p++ = gameepisode; [STRIFE] Doesn't have episodes.
+ *demo_p++ = gamemap;
+ *demo_p++ = deathmatch;
+ *demo_p++ = respawnparm;
+ *demo_p++ = fastparm;
+ *demo_p++ = nomonsters;
+ *demo_p++ = consoleplayer;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ *demo_p++ = playeringame[i];
+}
+
+
+//
+// G_PlayDemo
+//
+
+char* defdemoname;
+
+//
+// G_DeferedPlayDemo
+//
+// [STRIFE] Verified unmodified
+//
+void G_DeferedPlayDemo (char* name)
+{
+ defdemoname = name;
+ gameaction = ga_playdemo;
+}
+
+// Generate a string describing a demo version
+// [STRIFE] Modified to handle the one and only Strife demo version.
+static char *DemoVersionDescription(int version)
+{
+ static char resultbuf[16];
+
+ // [STRIFE] All versions of Strife 1.1 and later use 101 as their
+ // internal version number. Brilliant, huh? So we can't discern much
+ // here.
+
+ switch (version)
+ {
+ case 100:
+ return "v1.0"; // v1.0 would be the ancient demo version
+ default:
+ break;
+ }
+
+ // Unknown version. Who knows?
+ sprintf(resultbuf, "%i.%i (unknown)", version / 100, version % 100);
+
+ return resultbuf;
+}
+
+//
+// G_DoPlayDemo
+//
+// [STRIFE] Modified for Strife demo format.
+//
+void G_DoPlayDemo (void)
+{
+ skill_t skill;
+ int i, map;
+ int demoversion;
+
+ gameaction = ga_nothing;
+ demobuffer = demo_p = W_CacheLumpName (defdemoname, PU_STATIC);
+
+ demoversion = *demo_p++;
+
+ if (demoversion == STRIFE_VERSION)
+ {
+ longtics = false;
+ }
+ /* STRIFE-TODO: Not until/unless somebody makes a Strife-Plus :P
+ else if (demoversion == DOOM_191_VERSION)
+ {
+ // demo recorded with cph's modified "v1.91" doom exe
+ longtics = true;
+ }
+ */
+ else
+ {
+ char *message = "Demo is from a different game version!\n"
+ "(read %i, should be %i)\n"
+ "\n"
+ "*** You may need to upgrade your version "
+ "of Strife to v1.1 or later. ***\n"
+ " See: http://doomworld.com/files/patches.shtml\n"
+ " This appears to be %s.";
+
+ I_Error(message, demoversion, STRIFE_VERSION,
+ DemoVersionDescription(demoversion));
+ }
+
+ skill = *demo_p++;
+ //episode = *demo_p++; [STRIFE] No episodes
+ map = *demo_p++;
+ deathmatch = *demo_p++;
+ respawnparm = *demo_p++;
+ fastparm = *demo_p++;
+ nomonsters = *demo_p++;
+ consoleplayer = *demo_p++;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ playeringame[i] = *demo_p++;
+
+ //!
+ // @category demo
+ //
+ // Play back a demo recorded in a netgame with a single player.
+ //
+
+ if (playeringame[1] || M_CheckParm("-solo-net") > 0
+ || M_CheckParm("-netdemo") > 0)
+ {
+ netgame = true;
+ netdemo = true;
+ }
+
+ // don't spend a lot of time in loadlevel
+ precache = false;
+ G_InitNew(skill, map);
+ precache = true;
+
+ // [STRIFE] not here...
+ //starttime = I_GetTime ();
+
+ usergame = false;
+ demoplayback = true;
+}
+
+//
+// G_TimeDemo
+//
+// [STRIFE] Verified unmodified
+//
+void G_TimeDemo (char* name)
+{
+ //!
+ // @vanilla
+ //
+ // Disable rendering the screen entirely.
+ //
+
+ nodrawers = M_CheckParm ("-nodraw");
+
+ 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
+===================
+*/
+//
+// [STRIFE] Verified unmodified
+//
+boolean G_CheckDemoStatus (void)
+{
+ int endtime;
+
+ if (timingdemo)
+ {
+ float fps;
+ int realtics;
+
+ endtime = I_GetTime ();
+ realtics = endtime - starttime;
+ fps = ((float) gametic * TICRATE) / realtics;
+
+ // Prevent recursive calls
+ timingdemo = false;
+ demoplayback = false;
+
+ I_Error ("timed %i gametics in %i realtics (%f fps)",
+ gametic, realtics, fps);
+ }
+
+ if (demoplayback)
+ {
+ W_ReleaseLumpName(defdemoname);
+ demoplayback = false;
+ netdemo = false;
+ netgame = false;
+ deathmatch = false;
+ playeringame[1] = playeringame[2] = playeringame[3] = 0;
+ respawnparm = false;
+ fastparm = false;
+ nomonsters = false;
+ consoleplayer = 0;
+
+ if (singledemo)
+ I_Quit ();
+ else
+ D_AdvanceDemo ();
+
+ return true;
+ }
+
+ if (demorecording)
+ {
+ *demo_p++ = DEMOMARKER;
+ M_WriteFile (demoname, demobuffer, demo_p - demobuffer);
+ Z_Free (demobuffer);
+ demorecording = false;
+ I_Error ("Demo %s recorded", demoname);
+ }
+
+ return false;
+}
diff --git a/src/strife/g_game.h b/src/strife/g_game.h
new file mode 100644
index 00000000..61b2d5de
--- /dev/null
+++ b/src/strife/g_game.h
@@ -0,0 +1,97 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// Duh.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __G_GAME__
+#define __G_GAME__
+
+#include "doomdef.h"
+#include "d_event.h"
+#include "d_ticcmd.h"
+#include "tables.h"
+
+//
+// GAME
+//
+void G_DeathMatchSpawnPlayer (int playernum);
+
+// [STRIFE] Removed episode parameter
+void G_InitNew (skill_t skill, int map);
+
+// Can be called by the startup code or M_Responder.
+// A normal game starts at map 1,
+// but a warp test can start elsewhere
+// [STRIFE] Removed episode parameter
+void G_DeferedInitNew (skill_t skill, int map);
+
+void G_DeferedPlayDemo (char* demo);
+
+// Can be called by the startup code or M_Responder,
+// calls P_SetupLevel or W_EnterWorld.
+void G_LoadGame (char* name);
+
+void G_DoLoadGame (boolean userload);
+
+// Called by M_Responder.
+void G_SaveGame (int slot, char* description);
+
+// Only called by startup code.
+void G_RecordDemo (char* name);
+
+void G_BeginRecording (void);
+
+void G_PlayDemo (char* name);
+void G_TimeDemo (char* name);
+boolean G_CheckDemoStatus (void);
+
+void G_RiftExitLevel(int map, int spot, angle_t angle); // [STRIFE]
+void G_ExitLevel (int dest);
+//void G_SecretExitLevel (void);
+
+void G_StartFinale(void); // [STRIFE]
+
+//void G_WorldDone (void);
+
+boolean G_RiftCheat(int riftSpotNum); // [STRIFE]
+
+// Read current data from inputs and build a player movement command.
+
+void G_BuildTiccmd (ticcmd_t *cmd, int maketic);
+
+void G_Ticker (void);
+boolean G_Responder (event_t* ev);
+
+void G_ScreenShot (void);
+
+void G_DrawMouseSpeedBox(void);
+
+// [STRIFE]
+boolean G_WriteSaveName(int slot, const char *charname);
+void G_ReadCurrent(const char *path);
+
+extern int vanilla_savegame_limit;
+extern int vanilla_demo_limit;
+#endif
diff --git a/src/strife/hu_lib.c b/src/strife/hu_lib.c
new file mode 100644
index 00000000..38ab644a
--- /dev/null
+++ b/src/strife/hu_lib.c
@@ -0,0 +1,482 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <ctype.h>
+
+#include "doomdef.h"
+#include "doomkeys.h"
+
+#include "v_video.h"
+#include "i_swap.h"
+
+#include "hu_lib.h"
+#include "r_local.h"
+#include "r_draw.h"
+#include "hu_stuff.h" // [STRIFE]
+
+// boolean : whether the screen is always erased
+#define noterased viewwindowx
+
+extern boolean automapactive; // in AM_map.c
+
+extern boolean D_PatchClipCallback(patch_t *patch, int x, int y); // [STRIFE]
+
+//
+// HUlib_drawYellowText
+//
+// haleyjd 20100918: [STRIFE] New function.
+//
+void HUlib_drawYellowText(int x, int y, char *text)
+{
+ int start_x = x;
+ char *rover = text;
+ char c;
+
+ while((c = *rover++))
+ {
+ if(c == '\n')
+ {
+ x = start_x;
+ y += 12;
+ continue;
+ }
+
+ // haleyjd 20110213: found MORE code ignored/misinterpreted by Hex-Rays:
+ // Underscores are replaced by spaces.
+ if(c == '_')
+ c = ' ';
+ else if (c == ' ' && x == start_x) // skip spaces at the start of a line
+ continue;
+
+ c = toupper(c) - HU_FONTSTART;
+
+ if(c >= 0 && c < HU_FONTSIZE)
+ {
+ patch_t *patch = yfont[(int) c];
+ int width = SHORT(patch->width);
+
+ if(x + width <= (SCREENWIDTH - 20))
+ {
+ // haleyjd: STRIFE-TODO: bit different than the exe... for now
+ if(!D_PatchClipCallback(patch, x + SHORT(patch->leftoffset),
+ y + SHORT(patch->topoffset)))
+ return;
+ V_DrawPatchDirect(x, y, patch);
+ x = x + width;
+ }
+ else
+ {
+ x = start_x;
+ --rover;
+ y += 12;
+ }
+ }
+ else
+ {
+ x += 4;
+ }
+ }
+}
+
+//
+// HUlib_init
+//
+// [STRIFE] Verified unmodified.
+//
+void HUlib_init(void)
+{
+}
+
+//
+// HUlib_clearTextLine
+//
+// [STRIFE] Verified unmodified.
+//
+void HUlib_clearTextLine(hu_textline_t* t)
+{
+ t->len = 0;
+ t->l[0] = 0;
+ t->needsupdate = true;
+}
+
+//
+// HUlib_initTextLine
+//
+// [STRIFE] Verified unmodified
+//
+void
+HUlib_initTextLine
+( hu_textline_t* t,
+ int x,
+ int y,
+ patch_t** f,
+ int sc )
+{
+ t->x = x;
+ t->y = y;
+ t->f = f;
+ t->sc = sc;
+ HUlib_clearTextLine(t);
+}
+
+//
+// HUlib_addCharToTextLine
+//
+// [STRIFE] Verified unmodified.
+//
+boolean
+HUlib_addCharToTextLine
+( hu_textline_t* t,
+ char ch )
+{
+ if (t->len == HU_MAXLINELENGTH)
+ return false;
+ else
+ {
+ t->l[t->len++] = ch;
+ t->l[t->len] = 0;
+ t->needsupdate = 4;
+ return true;
+ }
+}
+
+//
+// HUlib_delCharFromTextLine
+//
+// [STRIFE] Verified unmodified.
+//
+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
+//
+// haleyjd 09/18/10: [STRIFE] Modified to not draw underscores in text.
+//
+void
+HUlib_drawTextLine
+( hu_textline_t* l,
+ boolean drawcursor )
+{
+ int i;
+ int w;
+ int x;
+ unsigned char c;
+
+ // draw the new stuff
+ x = l->x;
+
+ for(i = 0; i < l->len; i++)
+ {
+ c = toupper(l->l[i]);
+ if (c != ' ' && c >= l->sc && c < '_') // [STRIFE]: Underscores excluded
+ {
+ w = SHORT(l->f[c - l->sc]->width);
+ if (x+w > SCREENWIDTH)
+ break;
+ V_DrawPatchDirect(x, l->y, l->f[c - l->sc]);
+ x += w;
+ }
+ else
+ {
+ x += 4;
+ if (x >= SCREENWIDTH)
+ break;
+ }
+ }
+
+ // draw the cursor if requested
+ if (drawcursor
+ && x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH)
+ {
+ V_DrawPatchDirect(x, l->y, l->f['_' - l->sc]);
+ }
+}
+
+//
+// HUlib_eraseTextLine
+//
+// sorta called by HU_Erase and just better darn get things straight
+//
+// [STRIFE] Verified unmodified.
+//
+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 (!automapactive &&
+ 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
+ {
+ R_VideoErase(yoffset, viewwindowx); // erase left border
+ R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx);
+ // erase right border
+ }
+ }
+ }
+
+ if (l->needsupdate) l->needsupdate--;
+}
+
+//
+// HUlib_initSText
+//
+// [STRIFE] Verified unmodified.
+//
+void
+HUlib_initSText
+( hu_stext_t* s,
+ int x,
+ int y,
+ int h,
+ patch_t** font,
+ int startchar,
+ 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);
+ }
+}
+
+//
+// HUlib_addLineToSText
+//
+// [STRIFE] Verified unmodified.
+//
+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
+//
+// [STRIFE] Verified unmodified.
+//
+void
+HUlib_addMessageToSText
+( hu_stext_t* s,
+ char* prefix,
+ 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
+//
+// [STRIFE] Verified unmodified.
+//
+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
+//
+// [STRIFE] Verified unmodified.
+//
+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;
+}
+
+//
+// HUlib_initIText
+//
+// [STRIFE] Verified unmodified.
+//
+void
+HUlib_initIText
+( hu_itext_t* it,
+ int x,
+ int y,
+ patch_t** font,
+ int startchar,
+ 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);
+}
+
+
+// The following deletion routines adhere to the left margin restriction
+// [STRIFE] Verified unmodified.
+void HUlib_delCharFromIText(hu_itext_t* it)
+{
+ if (it->l.len != it->lm)
+ HUlib_delCharFromTextLine(&it->l);
+}
+
+// [STRIFE] Verified unmodified.
+void HUlib_eraseLineFromIText(hu_itext_t* it)
+{
+ while (it->lm != it->l.len)
+ HUlib_delCharFromTextLine(&it->l);
+}
+
+// Resets left margin as well
+// [STRIFE] Verified unmodified.
+void HUlib_resetIText(hu_itext_t* it)
+{
+ it->lm = 0;
+ HUlib_clearTextLine(&it->l);
+}
+
+//
+// HUlib_addPrefixToIText
+//
+// [STRIFE] Verified unmodified.
+//
+void
+HUlib_addPrefixToIText
+( hu_itext_t* it,
+ char* str )
+{
+ while (*str)
+ HUlib_addCharToTextLine(&it->l, *(str++));
+ it->lm = it->l.len;
+}
+
+// wrapper function for handling general keyed input.
+// returns true if it ate the key
+// [STRIFE] Verified unmodified.
+boolean
+HUlib_keyInIText
+( hu_itext_t* it,
+ unsigned char ch )
+{
+ ch = toupper(ch);
+
+ if (ch >= ' ' && ch <= '_')
+ HUlib_addCharToTextLine(&it->l, (char) ch);
+ else if (ch == KEY_BACKSPACE)
+ HUlib_delCharFromIText(it);
+ else if (ch != KEY_ENTER)
+ return false; // did not eat key
+
+ return true; // ate the key
+}
+
+//
+// HUlib_drawIText
+//
+// [STRIFE] Verified unmodified.
+//
+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
+//
+// [STRIFE] Verified unmodified.
+//
+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/src/strife/hu_lib.h b/src/strife/hu_lib.h
new file mode 100644
index 00000000..2a087800
--- /dev/null
+++ b/src/strife/hu_lib.h
@@ -0,0 +1,193 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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"
+
+// font stuff
+#define HU_CHARERASE KEY_BACKSPACE
+
+#define HU_MAXLINES 4
+#define HU_MAXLINELENGTH 80
+
+//
+// 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;
+
+ patch_t** f; // font
+ int sc; // start character
+ char l[HU_MAXLINELENGTH+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;
+
+
+
+// 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, patch_t **f, int sc);
+
+// 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);
+
+// villsa [STRIFE]
+void HUlib_drawYellowText(int x, int y, char *text);
+
+
+//
+// Scrolling Text window widget routines
+//
+
+// ?
+void
+HUlib_initSText
+( hu_stext_t* s,
+ int x,
+ int y,
+ int h,
+ patch_t** font,
+ int startchar,
+ boolean* on );
+
+// add a new line
+void HUlib_addLineToSText(hu_stext_t* s);
+
+// ?
+void
+HUlib_addMessageToSText
+( hu_stext_t* s,
+ char* prefix,
+ char* msg );
+
+// draws stext
+void HUlib_drawSText(hu_stext_t* s);
+
+// erases all stext lines
+void HUlib_eraseSText(hu_stext_t* s);
+
+// Input Text Line widget routines
+void
+HUlib_initIText
+( hu_itext_t* it,
+ int x,
+ int y,
+ patch_t** font,
+ int startchar,
+ 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/src/strife/hu_stuff.c b/src/strife/hu_stuff.c
new file mode 100644
index 00000000..eae9d166
--- /dev/null
+++ b/src/strife/hu_stuff.c
@@ -0,0 +1,666 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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
+//
+//-----------------------------------------------------------------------------
+
+
+#include <ctype.h>
+
+#include "doomdef.h"
+#include "doomkeys.h"
+
+#include "z_zone.h"
+
+#include "deh_main.h"
+#include "i_swap.h"
+#include "i_video.h"
+
+#include "hu_stuff.h"
+#include "hu_lib.h"
+#include "m_controls.h"
+#include "w_wad.h"
+
+#include "s_sound.h"
+
+#include "doomstat.h"
+
+// Data.
+#include "dstrings.h"
+#include "sounds.h"
+
+//
+// Locally used constants, shortcuts.
+//
+#define HU_TITLE (mapnames[gamemap-1])
+#define HU_TITLEHEIGHT 1
+#define HU_TITLEX 0
+
+// haleyjd 09/01/10: [STRIFE] 167 -> 160 to move up level name
+#define HU_TITLEY (160 - SHORT(hu_font[0]->height))
+
+#define HU_INPUTTOGGLE 't'
+#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
+
+char *chat_macros[10] =
+{
+ HUSTR_CHATMACRO0,
+ HUSTR_CHATMACRO1,
+ HUSTR_CHATMACRO2,
+ HUSTR_CHATMACRO3,
+ HUSTR_CHATMACRO4,
+ HUSTR_CHATMACRO5,
+ HUSTR_CHATMACRO6,
+ HUSTR_CHATMACRO7,
+ HUSTR_CHATMACRO8,
+ HUSTR_CHATMACRO9
+};
+
+// villsa [STRIFE]
+char pnameprefixes[8][16] =
+{
+ "1: ",
+ "2: ",
+ "3: ",
+ "4: ",
+ "5: ",
+ "6: ",
+ "7: ",
+ "8: "
+};
+
+char* player_names[] =
+{
+ HUSTR_PLRGREEN,
+ HUSTR_PLRINDIGO,
+ HUSTR_PLRBROWN,
+ HUSTR_PLRRED
+};
+
+char chat_char; // remove later.
+static player_t* plr;
+patch_t* hu_font[HU_FONTSIZE];
+patch_t* yfont[HU_FONTSIZE]; // haleyjd 09/18/10: [STRIFE]
+static hu_textline_t w_title;
+boolean chat_on;
+static hu_itext_t w_chat;
+static boolean always_off = false;
+static char chat_dest[MAXPLAYERS];
+static hu_itext_t w_inputbuffer[MAXPLAYERS];
+
+static boolean message_on;
+boolean message_dontfuckwithme;
+static boolean message_nottobefuckedwith;
+
+static hu_stext_t w_message;
+static int message_counter;
+
+//extern int showMessages; [STRIFE] no such variable
+
+static boolean headsupactive = false;
+
+static char * nickname; // haleyjd 09/18/10: [STRIFE]
+
+//
+// Builtin map names.
+// The actual names can be found in DStrings.h.
+//
+
+// haleyjd 08/31/10: [STRIFE] Changed for Strife level names.
+// List of names for levels.
+
+char *mapnames[] =
+{
+ // Strife map names
+
+ // First "episode" - Quest to destroy the Order's Castle
+ HUSTR_1,
+ HUSTR_2,
+ HUSTR_3,
+ HUSTR_4,
+ HUSTR_5,
+ HUSTR_6,
+ HUSTR_7,
+ HUSTR_8,
+ HUSTR_9,
+
+ // Second "episode" - Kill the Bishop and Make a Choice
+ HUSTR_10,
+ HUSTR_11,
+ HUSTR_12,
+ HUSTR_13,
+ HUSTR_14,
+ HUSTR_15,
+ HUSTR_16,
+ HUSTR_17,
+ HUSTR_18,
+ HUSTR_19,
+
+ // Third "episode" - Shut down Factory, kill Loremaster and Entity
+ HUSTR_20,
+ HUSTR_21,
+ HUSTR_22,
+ HUSTR_23,
+ HUSTR_24,
+ HUSTR_25,
+ HUSTR_26,
+ HUSTR_27,
+ HUSTR_28,
+ HUSTR_29,
+
+ // "Secret" levels - Abandoned Base and Training Facility
+ HUSTR_30,
+ HUSTR_31,
+
+ // Demo version maps
+ HUSTR_32,
+ HUSTR_33,
+ HUSTR_34
+};
+
+//
+// HU_Init
+//
+// haleyjd 09/18/10: [STRIFE]
+// * Modified to load yfont along with hu_font.
+//
+void HU_Init(void)
+{
+ int i;
+ int j;
+ char buffer[9];
+
+ // load the heads-up font
+ j = HU_FONTSTART;
+ for (i=0;i<HU_FONTSIZE;i++)
+ {
+ DEH_snprintf(buffer, 9, "STCFN%.3d", j++);
+ hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
+
+ // haleyjd 09/18/10: load yfont as well; and yes, this is exactly
+ // how Rogue did it :P
+ buffer[2] = 'B';
+ yfont[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
+ }
+}
+
+//
+// HU_Stop
+//
+// [STRIFE] Verified unmodified.
+//
+void HU_Stop(void)
+{
+ headsupactive = false;
+}
+
+//
+// HU_Start
+//
+// haleyjd 09/18/10: [STRIFE] Added a hack for nickname at the end.
+//
+void HU_Start(void)
+{
+ int i;
+ char* s;
+
+ // haleyjd 20120211: [STRIFE] not called here.
+ //if (headsupactive)
+ // HU_Stop();
+
+ // haleyjd 20120211: [STRIFE] moved up
+ // create the map title widget
+ HUlib_initTextLine(&w_title,
+ HU_TITLEX, HU_TITLEY,
+ hu_font,
+ HU_FONTSTART);
+
+ // haleyjd 08/31/10: [STRIFE] Get proper map name.
+ s = HU_TITLE;
+
+ // [STRIFE] Removed Chex Quest stuff.
+
+ // dehacked substitution to get modified level name
+ s = DEH_String(s);
+
+ while (*s)
+ HUlib_addCharToTextLine(&w_title, *(s++));
+
+ // haleyjd 20120211: [STRIFE] check for headsupactive
+ if(!headsupactive)
+ {
+ plr = &players[consoleplayer];
+ message_on = false;
+ message_dontfuckwithme = false;
+ message_nottobefuckedwith = false;
+ chat_on = false;
+
+ // create the message widget
+ HUlib_initSText(&w_message,
+ HU_MSGX, HU_MSGY, HU_MSGHEIGHT,
+ hu_font,
+ HU_FONTSTART, &message_on);
+
+ // create the chat widget
+ HUlib_initIText(&w_chat,
+ HU_INPUTX, HU_INPUTY,
+ hu_font,
+ HU_FONTSTART, &chat_on);
+
+ // create the inputbuffer widgets
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ HUlib_initIText(&w_inputbuffer[i], 0, 0, 0, 0, &always_off);
+
+ headsupactive = true;
+
+ // haleyjd 09/18/10: [STRIFE] nickname weirdness.
+
+ // STRIFE-TODO: This shit crashes the game.
+ /*
+ if(nickname != pnameprefixes[consoleplayer])
+ {
+ if(*nickname)
+ {
+ DEH_printf("have one\n");
+ nickname = pnameprefixes[consoleplayer];
+ }
+ }
+ */
+ }
+}
+
+//
+// HU_Drawer
+//
+// [STRIFE] Verified unmodified.
+//
+void HU_Drawer(void)
+{
+ HUlib_drawSText(&w_message);
+ HUlib_drawIText(&w_chat);
+ if (automapactive)
+ HUlib_drawTextLine(&w_title, false);
+}
+
+//
+// HU_Erase
+//
+// [STRIFE] Verified unmodified.
+//
+void HU_Erase(void)
+{
+ HUlib_eraseSText(&w_message);
+ HUlib_eraseIText(&w_chat);
+ HUlib_eraseTextLine(&w_title);
+}
+
+//
+// HU_addMessage
+//
+// haleyjd 09/18/10: [STRIFE] New function
+// See if you can tell whether or not I had trouble with this :P
+// Looks to be extremely buggy, hackish, and error-prone.
+//
+// <Markov> This is definitely not the best that Rogue had to offer. Markov.
+//
+// Fastcall Registers: edx ebx
+// Temp Registers: esi edi
+void HU_addMessage(char *prefix, char *message)
+{
+ char c; // eax
+ int width = 0; // edx
+ char *rover1; // ebx (in first loop)
+ char *rover2; // ecx (in second loop)
+ char *bufptr; // ebx (in second loop)
+ char buffer[HU_MAXLINELENGTH+2]; // esp+52h
+
+ // Loop 1: Total up width of prefix.
+ rover1 = prefix;
+ if(rover1)
+ {
+ while((c = *rover1))
+ {
+ c = toupper(c) - HU_FONTSTART;
+ ++rover1;
+
+ if(c < 0 || c >= HU_FONTSIZE)
+ width += 4;
+ else
+ width += SHORT(hu_font[(int) c]->width);
+ }
+ }
+
+ // Loop 2: Copy as much of message into buffer as will fit on screen
+ bufptr = buffer;
+ rover2 = message;
+ while((c = *rover2))
+ {
+ if((c == ' ' || c == '-') && width > 285)
+ break;
+
+ *bufptr = c;
+ ++bufptr; // BUG: No check for overflow.
+ ++rover2;
+ c = toupper(c);
+
+ if(c == ' ' || c < '!' || c >= '_')
+ width += 4;
+ else
+ {
+ c -= HU_FONTSTART;
+ width += SHORT(hu_font[(int) c]->width);
+ }
+ }
+
+ // Too big to fit?
+ // BUG: doesn't consider by how much it's over.
+ if(width > 320)
+ {
+ // backup a char... hell if I know why.
+ --bufptr;
+ --rover2;
+ }
+
+ // rover2 is not at the end?
+ if((c = *rover2))
+ {
+ // if not ON a space...
+ if(c != ' ')
+ {
+ // back up both pointers til one is found.
+ // BUG: no check against LHS of buffer. Hurr!
+ while(*bufptr != ' ')
+ {
+ --bufptr;
+ --rover2;
+ }
+ }
+ }
+
+ *bufptr = '\0';
+
+ // Add two message lines.
+ HUlib_addMessageToSText(&w_message, prefix, buffer);
+ HUlib_addMessageToSText(&w_message, NULL, rover2);
+}
+
+//
+// HU_Ticker
+//
+// haleyjd 09/18/10: [STRIFE] Changes to split up message into two lines,
+// and support for player names (STRIFE-TODO: unfinished!)
+//
+void HU_Ticker(void)
+{
+ int i, rc;
+ char c;
+ //char *prefix; STRIFE-TODO
+
+ // tick down message counter if message is up
+ if (message_counter && !--message_counter)
+ {
+ message_on = false;
+ message_nottobefuckedwith = false;
+ }
+
+ // haleyjd 20110219: [STRIFE] this condition was removed
+ //if (showMessages || message_dontfuckwithme)
+ //{
+ // display message if necessary
+ if ((plr->message && !message_nottobefuckedwith)
+ || (plr->message && message_dontfuckwithme))
+ {
+ //HUlib_addMessageToSText(&w_message, 0, plr->message);
+ HU_addMessage(NULL, plr->message); // haleyjd [STRIFE]
+ plr->message = 0;
+ message_on = true;
+ message_counter = HU_MSGTIMEOUT;
+ message_nottobefuckedwith = message_dontfuckwithme;
+ message_dontfuckwithme = 0;
+ }
+ //} // else message_on = false;
+
+ // 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
+ {
+ 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))
+ {
+ // STRIFE-TODO: there is interaction with the player
+ // name prefixes array here...
+ HU_addMessage(DEH_String(player_names[i]),
+ w_inputbuffer[i].l.l);
+
+ message_nottobefuckedwith = true;
+ message_on = true;
+ message_counter = HU_MSGTIMEOUT;
+ S_StartSound(0, sfx_radio);
+ }
+ 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
+//
+// haleyjd 09/18/10: [STRIFE]
+// * No message is given if a chat queue overflow occurs.
+//
+void HU_queueChatChar(char c)
+{
+ chatchars[head] = c;
+ if (((head + 1) & (QUEUESIZE-1)) != tail)
+ {
+ head = (head + 1) & (QUEUESIZE-1);
+ }
+}
+
+//
+// HU_dequeueChatChar
+//
+// [STRIFE] Verified unmodified.
+//
+char HU_dequeueChatChar(void)
+{
+ char c;
+
+ if (head != tail)
+ {
+ c = chatchars[tail];
+ tail = (tail + 1) & (QUEUESIZE-1);
+ }
+ else
+ {
+ c = 0;
+ }
+
+ return c;
+}
+
+//
+// HU_Responder
+//
+// haleyjd 09/18/10: [STRIFE]
+// * Mostly unmodified, except:
+// - The default value of key_message_refresh is changed. That is handled
+// elsewhere in Choco, however.
+// - There is support for setting the player name through the chat
+// mechanism. This is a STRIFE-TODO.
+//
+boolean HU_Responder(event_t *ev)
+{
+ static char lastmessage[HU_MAXLINELENGTH+1];
+ char* macromessage;
+ boolean eatkey = 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_RSHIFT)
+ {
+ return false;
+ }
+ else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT)
+ {
+ altdown = ev->type == ev_keydown;
+ return false;
+ }
+
+ if (ev->type != ev_keydown)
+ return false;
+
+ if (!chat_on)
+ {
+ if (ev->data1 == key_message_refresh)
+ {
+ message_on = true;
+ message_counter = HU_MSGTIMEOUT;
+ eatkey = true;
+ }
+ else if (netgame && ev->data2 == key_multi_msg)
+ {
+ eatkey = chat_on = true;
+ HUlib_resetIText(&w_chat);
+ HU_queueChatChar(HU_BROADCAST);
+ }
+ else if (netgame && numplayers > 2)
+ {
+ // STRIFE-TODO: support for setting player names
+
+ for (i=0; i<MAXPLAYERS ; i++)
+ {
+ if (ev->data2 == key_multi_msgplayer[i])
+ {
+ if (playeringame[i] && i!=consoleplayer)
+ {
+ eatkey = chat_on = true;
+ HUlib_resetIText(&w_chat);
+ HU_queueChatChar(i+1);
+ break;
+ }
+ else if (i == consoleplayer)
+ {
+ num_nobrainers++;
+ if (num_nobrainers < 3)
+ plr->message = DEH_String(HUSTR_TALKTOSELF1);
+ else if (num_nobrainers < 6)
+ plr->message = DEH_String(HUSTR_TALKTOSELF2);
+ else if (num_nobrainers < 9)
+ plr->message = DEH_String(HUSTR_TALKTOSELF3);
+ else if (num_nobrainers < 32)
+ plr->message = DEH_String(HUSTR_TALKTOSELF4);
+ else
+ plr->message = DEH_String(HUSTR_TALKTOSELF5);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ c = ev->data2;
+ // send a macro
+ if (altdown)
+ {
+ c = c - '0';
+ if (c > 9)
+ return false;
+ // fprintf(stderr, "got here\n");
+ macromessage = chat_macros[c];
+
+ // kill last message with a '\n'
+ HU_queueChatChar(KEY_ENTER); // DEBUG!!!
+
+ // send the macro message
+ while (*macromessage)
+ HU_queueChatChar(*macromessage++);
+ HU_queueChatChar(KEY_ENTER);
+
+ // leave chat mode and notify that it was sent
+ chat_on = false;
+ strcpy(lastmessage, chat_macros[c]);
+ plr->message = lastmessage;
+ eatkey = true;
+ }
+ else
+ {
+ eatkey = HUlib_keyInIText(&w_chat, c);
+ if (eatkey)
+ {
+ // static unsigned char buf[20]; // DEBUG
+ HU_queueChatChar(c);
+
+ // sprintf(buf, "KEY: %d => %d", ev->data1, c);
+ // plr->message = buf;
+ }
+ if (c == KEY_ENTER)
+ {
+ chat_on = false;
+ if (w_chat.l.len)
+ {
+ strcpy(lastmessage, w_chat.l.l);
+ plr->message = lastmessage;
+ }
+ }
+ else if (c == KEY_ESCAPE)
+ chat_on = false;
+ }
+ }
+
+ return eatkey;
+}
diff --git a/src/strife/hu_stuff.h b/src/strife/hu_stuff.h
new file mode 100644
index 00000000..e245a42c
--- /dev/null
+++ b/src/strife/hu_stuff.h
@@ -0,0 +1,75 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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"
+#include "v_patch.h"
+
+//
+// Globally visible constants.
+//
+#define HU_FONTSTART '!' // the first font characters
+#define HU_FONTEND '_' // the last font characters
+
+// Calculate # of glyphs in font.
+#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
+
+#define HU_BROADCAST 9 // haleyjd [STRIFE] Changed 5 -> 9
+
+#define HU_MSGX 0
+#define HU_MSGY (SHORT(hu_font[0]->height) + 1) // [STRIFE]: DOOM bug fix
+#define HU_MSGWIDTH 64 // in characters
+#define HU_MSGHEIGHT 2 // in lines
+
+#define HU_MSGTIMEOUT (8*TICRATE) // haleyjd [STRIFE] Doubled message timeout
+
+
+//
+// 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);
+
+extern char *chat_macros[10];
+extern char pnameprefixes[8][16]; // villsa [STRIFE]
+
+// haleyjd [STRIFE] externalized:
+extern char *mapnames[];
+
+// [STRIFE]
+extern patch_t* yfont[HU_FONTSIZE]; // haleyjd 09/18/10: [STRIFE]
+
+#endif
+
diff --git a/src/strife/info.c b/src/strife/info.c
new file mode 100644
index 00000000..0d829f79
--- /dev/null
+++ b/src/strife/info.c
@@ -0,0 +1,11049 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// Data.
+#include "sounds.h"
+#include "m_fixed.h"
+
+#include "info.h"
+
+#include "p_mobj.h"
+
+// villsa [STRIFE]
+char *sprnames[NUMSPRITES+1] =
+{
+ "PLAY", "PNCH", "WAVE", "RBPY", "TRGT", "XBOW", "MMIS", "RIFG",
+ "RIFF", "FLMT", "FLMF", "BLST", "BLSF", "GREN", "GREF", "SIGH",
+ "SIGF", "POW1", "POW2", "POW3", "ZAP1", "SPRY", "BLOD", "PUFY",
+ "SHT1", "SHT2", "GRIN", "GRAP", "UBAM", "BNG2", "BNG4", "BNG3",
+ "FLBE", "XPRK", "OCLW", "CCLW", "TEND", "MICR", "MISS", "AROW",
+ "ARWP", "TORP", "THIT", "TWAV", "MISL", "TFOG", "IFOG", "SHRD",
+ "RGIB", "MRYS", "MRNO", "MRST", "MRLK", "MRBD", "MRPN", "MRGT",
+ "BURN", "DISR", "PEAS", "GIBS", "AGRD", "ARMR", "SACR", "TNK1",
+ "TNK2", "TNK3", "TNK4", "TNK5", "TNK6", "NEAL", "BEGR", "HMN1",
+ "LEDR", "LEAD", "ROB1", "PGRD", "ROB2", "MLDR", "ORCL", "PRST",
+ "PDED", "ALN1", "AL1P", "NODE", "MTHD", "MNAM", "MNAL", "MDTH",
+ "NEST", "PODD", "ZAP6", "ZOT3", "ZAP7", "ZOT1", "ZAP5", "ZOT2",
+ "SEWR", "SPID", "ROB3", "RBB3", "PRGR", "BASE", "FRBL", "KLAX",
+ "TURT", "BALL", "PSTN", "SECR", "TARG", "RING", "EARS", "COMM",
+ "BOOM", "RATT", "HOGN", "DEAD", "SBAN", "BOTR", "HATR", "TOPR",
+ "COUP", "BUBB", "BUBF", "BUBC", "ASPR", "SPDL", "TOKN", "OTOK",
+ "HELT", "GUNT", "FULL", "MEAT", "JUNK", "FFOT", "DIE1", "BEAC",
+ "ARM1", "ARM2", "BARW", "BART", "LAMP", "LANT", "BARL", "BOWL",
+ "BRAZ", "TRCH", "LTRH", "LMPC", "LOGS", "TRHO", "WATR", "MUGG",
+ "FUSL", "CRD1", "CRD2", "TPAS", "KY1G", "KY2S", "KY3B", "HAND",
+ "CRYS", "PRIS", "PWR1", "PWR2", "PWR3", "ORAC", "GYID", "FUBR",
+ "WARE", "RCRY", "BCRY", "CHAP", "TUNL", "BLTK", "SECK", "MINE",
+ "REBL", "PROC", "ANKH", "GOID", "STMP", "MDKT", "COIN", "CRED",
+ "SACK", "CHST", "SHD1", "MASK", "UNIF", "OFIC", "PMAP", "PMUP",
+ "BLIT", "BBOX", "MSSL", "ROKT", "BRY1", "CPAC", "PQRL", "XQRL",
+ "GRN1", "GRN2", "BKPK", "RELC", "RIFL", "FLAM", "BFLM", "MMSL",
+ "TRPD", "GRND", "CBOW", "SIGL", "LITE", "CNDL", "CLBR", "LITS",
+ "LITB", "LITG", "ROK1", "ROK2", "ROK3", "ROK4", "LOGG", "RUB1",
+ "RUB2", "RUB3", "RUB4", "RUB5", "RUB6", "RUB7", "RUB8", "CHAN",
+ "STAT", "DSTA", "CRAB", "CAGE", "TREE", "TRE1", "BUSH", "SHRB",
+ "STAK", "BAR1", "VASE", "STOL", "POT1", "TUB1", "ANVL", "TLMP",
+ "TRAY", "APOW", "AFED", "DRIP", "CDRP", "SPLH", "WTFT", "HERT",
+ "TELP", "MONI", "STEL", "STLA", "STLE", "HUGE", "STLG", NULL
+};
+
+
+// Doesn't work with g++, needs actionf_p1
+// villsa [STRIFE]
+void A_Look();
+void A_RandomWalk();
+void A_FriendLook();
+void A_Listen();
+void A_Chase();
+void A_FaceTarget();
+void A_PeasantPunch();
+void A_ReaverAttack();
+void A_BulletAttack();
+void A_CheckTargetVisible();
+void A_SentinelAttack();
+void A_StalkerThink();
+void A_StalkerSetLook();
+void A_StalkerDrop();
+void A_StalkerScratch();
+void A_FloatWeave();
+void A_RobotMelee();
+void A_TemplarMauler();
+void A_CrusaderAttack();
+void A_CrusaderLeft();
+void A_CrusaderRight();
+void A_CheckTargetVisible2();
+void A_InqFlyCheck();
+void A_InqGrenade();
+void A_InqTakeOff();
+void A_InqFly();
+void A_FireSigilWeapon();
+void A_ProgrammerAttack();
+void A_Sigil_A_Action();
+void A_SpectreEAttack();
+void A_SpectreCAttack();
+void A_AlertSpectreC();
+void A_Sigil_E_Action();
+void A_SigilTrail();
+void A_SpectreDAttack();
+void A_FireSigilEOffshoot();
+void A_ShadowOff();
+void A_ModifyVisibility();
+void A_ShadowOn();
+void A_SetTLOptions();
+void A_BossMeleeAtk();
+void A_BishopAttack();
+void A_FireHookShot();
+void A_FireChainShot();
+void A_MissileSmoke();
+void A_SpawnSparkPuff();
+void A_Tracer();
+void A_ProgrammerMelee();
+void A_Scream();
+void A_XScream();
+void A_Pain();
+void A_PeasantCrash();
+void A_Fall();
+void A_HideZombie();
+void A_MerchantPain();
+void A_ProgrammerDie();
+void A_InqTossArm();
+void A_SpawnSpectreB();
+void A_SpawnSpectreD();
+void A_SpawnSpectreE();
+void A_SpawnEntity();
+void A_EntityDeath();
+void A_SpawnZombie();
+void A_ZombieInSpecialSector();
+void A_CrystalExplode();
+void A_QuestMsg();
+void A_ExtraLightOff();
+void A_CrystalRadiusAtk();
+void A_DeathExplode5();
+void A_DeathExplode1();
+void A_DeathExplode2();
+void A_DeathExplode3();
+void A_RaiseAlarm();
+void A_MissileTick();
+void A_SpawnGrenadeFire();
+void A_NodeChunk();
+void A_HeadChunk();
+void A_BurnSpread();
+void A_AcolyteSpecial();
+void A_BossDeath();
+void A_InqChase();
+void A_StalkerChase();
+void A_PlayerScream();
+void A_TeleportBeacon();
+void A_BodyParts();
+void A_ClaxonBlare();
+void A_ActiveSound();
+void A_ClearSoundTarget();
+void A_DropBurnFlesh();
+void A_FlameDeath();
+void A_ClearForceField();
+void A_WeaponReady();
+void A_ReFire();
+void A_CheckReload();
+void A_Lower();
+void A_Raise();
+void A_GunFlash();
+void A_Punch();
+void A_FireFlameThrower();
+void A_FireMissile();
+void A_FireMauler2();
+void A_FireGrenade();
+void A_FireElectricBolt();
+void A_FirePoisonBolt();
+void A_FireRifle();
+void A_FireMauler1();
+void A_SigilSound();
+void A_FireSigil();
+void A_GunFlashThinker();
+void A_Light0();
+void A_Light1();
+void A_Light2();
+void A_SigilShock();
+void A_TorpedoExplode();
+void A_MaulerSound();
+
+// villsa [STRIFE]
+state_t states[NUMSTATES] =
+{
+
+/*S_NULL*/ { SPR_PLAY, 0, -1, { NULL }, S_NULL }, //00
+/*S_PNCH_00*/ { SPR_PNCH, 0, 0, { A_Light0 }, S_NULL }, //01
+/*S_WAVE_00*/ { SPR_WAVE, 32768, 3, { NULL }, S_WAVE_01 }, //02
+/*S_WAVE_01*/ { SPR_WAVE, 32769, 3, { NULL }, S_WAVE_02 }, //03
+/*S_WAVE_02*/ { SPR_WAVE, 32770, 3, { NULL }, S_WAVE_03 }, //04
+/*S_WAVE_03*/ { SPR_WAVE, 32771, 3, { NULL }, S_WAVE_00 }, //05
+/*S_RBPY_00*/ { SPR_RBPY, 32768, 3, { NULL }, S_RBPY_01 }, //06
+/*S_RBPY_01*/ { SPR_RBPY, 32769, 3, { NULL }, S_RBPY_02 }, //07
+/*S_RBPY_02*/ { SPR_RBPY, 32770, 3, { NULL }, S_RBPY_03 }, //08
+/*S_RBPY_03*/ { SPR_RBPY, 32771, 3, { NULL }, S_RBPY_00 }, //09
+/*S_TRGT_00*/ { SPR_TRGT, 0, -1, { NULL }, S_NULL }, //10
+/*S_TRGT_01*/ { SPR_TRGT, 1, -1, { NULL }, S_NULL }, //11
+/*S_TRGT_02*/ { SPR_TRGT, 2, -1, { NULL }, S_NULL }, //12
+/*S_PNCH_01*/ { SPR_PNCH, 0, 1, { A_WeaponReady }, S_PNCH_01 }, //13
+/*S_PNCH_02*/ { SPR_PNCH, 0, 1, { A_Lower }, S_PNCH_02 }, //14
+/*S_PNCH_03*/ { SPR_PNCH, 0, 1, { A_Raise }, S_PNCH_03 }, //15
+/*S_PNCH_04*/ { SPR_PNCH, 1, 4, { NULL }, S_PNCH_05 }, //16
+/*S_PNCH_05*/ { SPR_PNCH, 2, 4, { A_Punch }, S_PNCH_06 }, //17
+/*S_PNCH_06*/ { SPR_PNCH, 3, 5, { NULL }, S_PNCH_07 }, //18
+/*S_PNCH_07*/ { SPR_PNCH, 2, 4, { NULL }, S_PNCH_08 }, //19
+/*S_PNCH_08*/ { SPR_PNCH, 1, 5, { A_ReFire }, S_PNCH_01 }, //20
+/*S_XBOW_00*/ { SPR_XBOW, 0, 1, { A_WeaponReady }, S_XBOW_00 }, //21
+/*S_XBOW_01*/ { SPR_XBOW, 0, 1, { A_Lower }, S_XBOW_01 }, //22
+/*S_XBOW_02*/ { SPR_XBOW, 0, 1, { A_Raise }, S_XBOW_02 }, //23
+/*S_XBOW_03*/ { SPR_XBOW, 0, 3, { A_GunFlashThinker }, S_XBOW_04 }, //24
+/*S_XBOW_04*/ { SPR_XBOW, 1, 6, { A_FireElectricBolt }, S_XBOW_05 }, //25
+/*S_XBOW_05*/ { SPR_XBOW, 2, 4, { NULL }, S_XBOW_06 }, //26
+/*S_XBOW_06*/ { SPR_XBOW, 3, 6, { NULL }, S_XBOW_07 }, //27
+/*S_XBOW_07*/ { SPR_XBOW, 4, 3, { NULL }, S_XBOW_08 }, //28
+/*S_XBOW_08*/ { SPR_XBOW, 5, 5, { NULL }, S_XBOW_09 }, //29
+/*S_XBOW_09*/ { SPR_XBOW, 6, 5, { A_CheckReload }, S_XBOW_00 }, //30
+/*S_XBOW_10*/ { SPR_XBOW, 10, 5, { NULL }, S_XBOW_11 }, //31
+/*S_XBOW_11*/ { SPR_XBOW, 11, 5, { NULL }, S_XBOW_12 }, //32
+/*S_XBOW_12*/ { SPR_XBOW, 12, 5, { NULL }, S_XBOW_10 }, //33
+/*S_XBOW_13*/ { SPR_XBOW, 7, 1, { A_WeaponReady }, S_XBOW_13 }, //34
+/*S_XBOW_14*/ { SPR_XBOW, 7, 1, { A_Lower }, S_XBOW_14 }, //35
+/*S_XBOW_15*/ { SPR_XBOW, 7, 1, { A_Raise }, S_XBOW_15 }, //36
+/*S_XBOW_16*/ { SPR_XBOW, 7, 3, { NULL }, S_XBOW_17 }, //37
+/*S_XBOW_17*/ { SPR_XBOW, 1, 6, { A_FirePoisonBolt }, S_XBOW_18 }, //38
+/*S_XBOW_18*/ { SPR_XBOW, 2, 4, { NULL }, S_XBOW_19 }, //39
+/*S_XBOW_19*/ { SPR_XBOW, 3, 6, { NULL }, S_XBOW_20 }, //40
+/*S_XBOW_20*/ { SPR_XBOW, 4, 3, { NULL }, S_XBOW_21 }, //41
+/*S_XBOW_21*/ { SPR_XBOW, 8, 5, { NULL }, S_XBOW_22 }, //42
+/*S_XBOW_22*/ { SPR_XBOW, 9, 5, { A_CheckReload }, S_XBOW_13 }, //43
+/*S_MMIS_00*/ { SPR_MMIS, 0, 1, { A_WeaponReady }, S_MMIS_00 }, //44
+/*S_MMIS_01*/ { SPR_MMIS, 0, 1, { A_Lower }, S_MMIS_01 }, //45
+/*S_MMIS_02*/ { SPR_MMIS, 0, 1, { A_Raise }, S_MMIS_02 }, //46
+/*S_MMIS_03*/ { SPR_MMIS, 0, 4, { A_FireMissile }, S_MMIS_04 }, //47
+/*S_MMIS_04*/ { SPR_MMIS, 1, 4, { A_Light1 }, S_MMIS_05 }, //48
+/*S_MMIS_05*/ { SPR_MMIS, 32770, 5, { NULL }, S_MMIS_06 }, //49
+/*S_MMIS_06*/ { SPR_MMIS, 32771, 2, { A_Light2 }, S_MMIS_07 }, //50
+/*S_MMIS_07*/ { SPR_MMIS, 32772, 2, { NULL }, S_MMIS_08 }, //51
+/*S_MMIS_08*/ { SPR_MMIS, 32773, 2, { A_Light0 }, S_MMIS_09 }, //52
+/*S_MMIS_09*/ { SPR_MMIS, 5, 0, { A_ReFire }, S_MMIS_00 }, //53
+/*S_RIFG_00*/ { SPR_RIFG, 0, 1, { A_WeaponReady }, S_RIFG_00 }, //54
+/*S_RIFG_01*/ { SPR_RIFG, 1, 1, { A_Lower }, S_RIFG_01 }, //55
+/*S_RIFG_02*/ { SPR_RIFG, 0, 1, { A_Raise }, S_RIFG_02 }, //56
+/*S_RIFF_00*/ { SPR_RIFF, 0, 3, { A_FireRifle }, S_RIFF_01 }, //57
+/*S_RIFF_01*/ { SPR_RIFF, 1, 3, { A_FireRifle }, S_RIFG_03 }, //58
+/*S_RIFG_03*/ { SPR_RIFG, 3, 3, { A_FireRifle }, S_RIFG_04 }, //59
+/*S_RIFG_04*/ { SPR_RIFG, 2, 0, { A_ReFire }, S_RIFG_05 }, //60
+/*S_RIFG_05*/ { SPR_RIFG, 1, 2, { NULL }, S_RIFG_00 }, //61
+/*S_FLMT_00*/ { SPR_FLMT, 0, 3, { A_WeaponReady }, S_FLMT_01 }, //62
+/*S_FLMT_01*/ { SPR_FLMT, 1, 3, { A_WeaponReady }, S_FLMT_00 }, //63
+/*S_FLMT_02*/ { SPR_FLMT, 0, 1, { A_Lower }, S_FLMT_02 }, //64
+/*S_FLMT_03*/ { SPR_FLMT, 0, 1, { A_Raise }, S_FLMT_03 }, //65
+/*S_FLMF_00*/ { SPR_FLMF, 0, 2, { A_FireFlameThrower }, S_FLMF_01 }, //66
+/*S_FLMF_01*/ { SPR_FLMF, 1, 3, { A_ReFire }, S_FLMT_00 }, //67
+/*S_BLST_00*/ { SPR_BLST, 5, 6, { A_WeaponReady }, S_BLST_01 }, //68
+/*S_BLST_01*/ { SPR_BLST, 6, 6, { A_WeaponReady }, S_BLST_02 }, //69
+/*S_BLST_02*/ { SPR_BLST, 7, 6, { A_WeaponReady }, S_BLST_03 }, //70
+/*S_BLST_03*/ { SPR_BLST, 0, 6, { A_WeaponReady }, S_BLST_00 }, //71
+/*S_BLST_04*/ { SPR_BLST, 0, 1, { A_Lower }, S_BLST_04 }, //72
+/*S_BLST_05*/ { SPR_BLST, 0, 1, { A_Raise }, S_BLST_05 }, //73
+/*S_BLSF_00*/ { SPR_BLSF, 32768, 5, { A_FireMauler1 }, S_BLST_06 }, //74
+/*S_BLST_06*/ { SPR_BLST, 32769, 3, { A_Light1 }, S_BLST_07 }, //75
+/*S_BLST_07*/ { SPR_BLST, 2, 2, { A_Light2 }, S_BLST_08 }, //76
+/*S_BLST_08*/ { SPR_BLST, 3, 2, { NULL }, S_BLST_09 }, //77
+/*S_BLST_09*/ { SPR_BLST, 4, 2, { NULL }, S_BLST_10 }, //78
+/*S_BLST_10*/ { SPR_BLST, 0, 7, { A_Light0 }, S_BLST_11 }, //79
+/*S_BLST_11*/ { SPR_BLST, 7, 7, { NULL }, S_BLST_12 }, //80
+/*S_BLST_12*/ { SPR_BLST, 6, 7, { A_CheckReload }, S_BLST_00 }, //81
+/*S_BLST_13*/ { SPR_BLST, 8, 7, { A_WeaponReady }, S_BLST_14 }, //82
+/*S_BLST_14*/ { SPR_BLST, 9, 7, { A_WeaponReady }, S_BLST_15 }, //83
+/*S_BLST_15*/ { SPR_BLST, 10, 7, { A_WeaponReady }, S_BLST_16 }, //84
+/*S_BLST_16*/ { SPR_BLST, 11, 7, { A_WeaponReady }, S_BLST_13 }, //85
+/*S_BLST_17*/ { SPR_BLST, 8, 1, { A_Lower }, S_BLST_17 }, //86
+/*S_BLST_18*/ { SPR_BLST, 8, 1, { A_Raise }, S_BLST_18 }, //87
+/*S_BLST_19*/ { SPR_BLST, 8, 20, { A_MaulerSound }, S_BLST_20 }, //88
+/*S_BLST_20*/ { SPR_BLST, 9, 10, { A_Light1 }, S_BLSF_01 }, //89
+/*S_BLSF_01*/ { SPR_BLSF, 32768, 10, { A_FireMauler2 }, S_BLST_21 }, //90
+/*S_BLST_21*/ { SPR_BLST, 32769, 3, { A_Light2 }, S_BLST_22 }, //91
+/*S_BLST_22*/ { SPR_BLST, 2, 2, { NULL }, S_BLST_23 }, //92
+/*S_BLST_23*/ { SPR_BLST, 3, 2, { A_Light0 }, S_BLST_24 }, //93
+/*S_BLST_24*/ { SPR_BLST, 4, 2, { A_ReFire }, S_BLST_13 }, //94
+/*S_GREN_00*/ { SPR_GREN, 0, 1, { A_WeaponReady }, S_GREN_00 }, //95
+/*S_GREN_01*/ { SPR_GREN, 0, 1, { A_Lower }, S_GREN_01 }, //96
+/*S_GREN_02*/ { SPR_GREN, 0, 1, { A_Raise }, S_GREN_02 }, //97
+/*S_GREN_03*/ { SPR_GREN, 0, 5, { A_FireGrenade }, S_GREN_04 }, //98
+/*S_GREN_04*/ { SPR_GREN, 1, 10, { NULL }, S_GREN_05 }, //99
+/*S_GREN_05*/ { SPR_GREN, 0, 5, { A_FireGrenade }, S_GREN_06 }, //100
+/*S_GREN_06*/ { SPR_GREN, 2, 10, { NULL }, S_GREN_07 }, //101
+/*S_GREN_07*/ { SPR_GREN, 0, 0, { A_ReFire }, S_GREN_00 }, //102
+/*S_GREF_00*/ { SPR_GREF, 32768, 5, { A_Light1 }, S_PNCH_00 }, //103
+/*S_GREF_01*/ { SPR_GREF, 0, 10, { A_Light0 }, S_PNCH_00 }, //104
+/*S_GREF_02*/ { SPR_GREF, 32769, 5, { A_Light2 }, S_PNCH_00 }, //105
+/*S_GREN_08*/ { SPR_GREN, 3, 1, { A_WeaponReady }, S_GREN_08 }, //106
+/*S_GREN_09*/ { SPR_GREN, 3, 1, { A_Lower }, S_GREN_09 }, //107
+/*S_GREN_10*/ { SPR_GREN, 3, 1, { A_Raise }, S_GREN_10 }, //108
+/*S_GREN_11*/ { SPR_GREN, 3, 5, { A_FireGrenade }, S_GREN_12 }, //109
+/*S_GREN_12*/ { SPR_GREN, 4, 10, { NULL }, S_GREN_13 }, //110
+/*S_GREN_13*/ { SPR_GREN, 3, 5, { A_FireGrenade }, S_GREN_14 }, //111
+/*S_GREN_14*/ { SPR_GREN, 5, 10, { NULL }, S_GREN_15 }, //112
+/*S_GREN_15*/ { SPR_GREN, 0, 0, { A_ReFire }, S_GREN_08 }, //113
+/*S_GREF_03*/ { SPR_GREF, 32770, 5, { A_Light1 }, S_PNCH_00 }, //114
+/*S_GREF_04*/ { SPR_GREF, 2, 10, { A_Light0 }, S_PNCH_00 }, //115
+/*S_GREF_05*/ { SPR_GREF, 32771, 5, { A_Light2 }, S_PNCH_00 }, //116
+/*S_SIGH_00*/ { SPR_SIGH, 32768, 1, { A_WeaponReady }, S_SIGH_00 }, //117
+/*S_SIGH_01*/ { SPR_SIGH, 32769, -1, { NULL }, S_NULL }, //118
+/*S_SIGH_02*/ { SPR_SIGH, 32770, -1, { NULL }, S_NULL }, //119
+/*S_SIGH_03*/ { SPR_SIGH, 32771, -1, { NULL }, S_NULL }, //120
+/*S_SIGH_04*/ { SPR_SIGH, 32772, -1, { NULL }, S_NULL }, //121
+/*S_SIGH_05*/ { SPR_SIGH, 32768, 1, { A_Lower }, S_SIGH_05 }, //122
+/*S_SIGH_06*/ { SPR_SIGH, 32768, 1, { A_Raise }, S_SIGH_06 }, //123
+/*S_SIGH_07*/ { SPR_SIGH, 32768, 18, { A_SigilSound }, S_SIGH_08 }, //124
+/*S_SIGH_08*/ { SPR_SIGH, 32768, 3, { A_GunFlash }, S_SIGH_09 }, //125
+/*S_SIGH_09*/ { SPR_SIGH, 0, 10, { A_FireSigil }, S_SIGH_10 }, //126
+/*S_SIGH_10*/ { SPR_SIGH, 0, 5, { A_GunFlashThinker }, S_SIGH_00 }, //127
+/*S_SIGF_00*/ { SPR_SIGF, 32768, 4, { A_Light2 }, S_SIGF_01 }, //128
+/*S_SIGF_01*/ { SPR_SIGF, 32769, 6, { A_SigilShock }, S_SIGF_02 }, //129
+/*S_SIGF_02*/ { SPR_SIGF, 32770, 4, { A_Light1 }, S_PNCH_00 }, //130
+/*S_POW1_00*/ { SPR_POW1, 0, 4, { NULL }, S_POW1_01 }, //131
+/*S_POW1_01*/ { SPR_POW1, 1, 4, { NULL }, S_POW1_02 }, //132
+/*S_POW1_02*/ { SPR_POW1, 2, 4, { NULL }, S_POW1_03 }, //133
+/*S_POW1_03*/ { SPR_POW1, 3, 4, { NULL }, S_POW1_04 }, //134
+/*S_POW1_04*/ { SPR_POW1, 4, 4, { NULL }, S_NULL }, //135
+/*S_POW1_05*/ { SPR_POW1, 5, 4, { NULL }, S_POW1_06 }, //136
+/*S_POW1_06*/ { SPR_POW1, 6, 4, { NULL }, S_POW1_07 }, //137
+/*S_POW1_07*/ { SPR_POW1, 7, 4, { NULL }, S_POW1_08 }, //138
+/*S_POW1_08*/ { SPR_POW1, 8, 4, { NULL }, S_POW1_09 }, //139
+/*S_POW1_09*/ { SPR_POW1, 9, 4, { NULL }, S_NULL }, //140
+/*S_POW2_00*/ { SPR_POW2, 0, 4, { NULL }, S_POW2_01 }, //141
+/*S_POW2_01*/ { SPR_POW2, 1, 4, { NULL }, S_POW2_02 }, //142
+/*S_POW2_02*/ { SPR_POW2, 2, 4, { NULL }, S_POW2_03 }, //143
+/*S_POW2_03*/ { SPR_POW2, 3, 4, { NULL }, S_NULL }, //144
+/*S_POW3_00*/ { SPR_POW3, 0, 3, { NULL }, S_POW3_01 }, //145
+/*S_POW3_01*/ { SPR_POW3, 1, 3, { NULL }, S_POW3_02 }, //146
+/*S_POW3_02*/ { SPR_POW3, 2, 3, { NULL }, S_POW3_03 }, //147
+/*S_POW3_03*/ { SPR_POW3, 3, 3, { NULL }, S_POW3_04 }, //148
+/*S_POW3_04*/ { SPR_POW3, 4, 3, { NULL }, S_POW3_05 }, //149
+/*S_POW3_05*/ { SPR_POW3, 5, 3, { NULL }, S_POW3_06 }, //150
+/*S_POW3_06*/ { SPR_POW3, 6, 3, { NULL }, S_POW3_07 }, //151
+/*S_POW3_07*/ { SPR_POW3, 7, 3, { NULL }, S_NULL }, //152
+/*S_ZAP1_00*/ { SPR_ZAP1, 1, 3, { A_DeathExplode3 }, S_ZAP1_02 }, //153
+/*S_ZAP1_01*/ { SPR_ZAP1, 0, 3, { A_RaiseAlarm }, S_ZAP1_02 }, //154
+/*S_ZAP1_02*/ { SPR_ZAP1, 1, 3, { NULL }, S_ZAP1_03 }, //155
+/*S_ZAP1_03*/ { SPR_ZAP1, 2, 3, { NULL }, S_ZAP1_04 }, //156
+/*S_ZAP1_04*/ { SPR_ZAP1, 3, 3, { NULL }, S_ZAP1_05 }, //157
+/*S_ZAP1_05*/ { SPR_ZAP1, 4, 3, { NULL }, S_ZAP1_06 }, //158
+/*S_ZAP1_06*/ { SPR_ZAP1, 5, 3, { NULL }, S_ZAP1_07 }, //159
+/*S_ZAP1_07*/ { SPR_ZAP1, 4, 3, { NULL }, S_ZAP1_08 }, //160
+/*S_ZAP1_08*/ { SPR_ZAP1, 3, 2, { NULL }, S_ZAP1_09 }, //161
+/*S_ZAP1_09*/ { SPR_ZAP1, 2, 2, { NULL }, S_ZAP1_10 }, //162
+/*S_ZAP1_10*/ { SPR_ZAP1, 1, 2, { NULL }, S_ZAP1_11 }, //163
+/*S_ZAP1_11*/ { SPR_ZAP1, 0, 1, { NULL }, S_NULL }, //164
+/*S_SPRY_00*/ { SPR_SPRY, 0, 3, { NULL }, S_SPRY_01 }, //165
+/*S_SPRY_01*/ { SPR_SPRY, 1, 3, { NULL }, S_SPRY_02 }, //166
+/*S_SPRY_02*/ { SPR_SPRY, 2, 3, { NULL }, S_SPRY_03 }, //167
+/*S_SPRY_03*/ { SPR_SPRY, 3, 3, { NULL }, S_SPRY_04 }, //168
+/*S_SPRY_04*/ { SPR_SPRY, 4, 3, { NULL }, S_SPRY_05 }, //169
+/*S_SPRY_05*/ { SPR_SPRY, 5, 3, { NULL }, S_SPRY_06 }, //170
+/*S_SPRY_06*/ { SPR_SPRY, 6, 2, { NULL }, S_NULL }, //171
+/*S_BLOD_00*/ { SPR_BLOD, 2, 8, { NULL }, S_BLOD_01 }, //172
+/*S_BLOD_01*/ { SPR_BLOD, 1, 8, { NULL }, S_BLOD_02 }, //173
+/*S_BLOD_02*/ { SPR_BLOD, 0, 8, { NULL }, S_NULL }, //174
+/*S_PUFY_00*/ { SPR_PUFY, 32768, 4, { NULL }, S_PUFY_01 }, //175
+/*S_PUFY_01*/ { SPR_PUFY, 1, 4, { NULL }, S_PUFY_02 }, //176
+/*S_PUFY_02*/ { SPR_PUFY, 2, 4, { NULL }, S_PUFY_03 }, //177
+/*S_PUFY_03*/ { SPR_PUFY, 3, 4, { NULL }, S_NULL }, //178
+/*S_SHT1_00*/ { SPR_SHT1, 0, 4, { NULL }, S_SHT1_01 }, //179
+/*S_SHT1_01*/ { SPR_SHT1, 1, 4, { NULL }, S_SHT1_00 }, //180
+/*S_SHT2_00*/ { SPR_SHT2, 0, 5, { NULL }, S_SHT2_01 }, //181
+/*S_SHT2_01*/ { SPR_SHT2, 1, 5, { NULL }, S_POW1_00 }, //182
+/*S_GRIN_00*/ { SPR_GRIN, 0, 3, { A_MissileTick }, S_GRIN_01 }, //183
+/*S_GRIN_01*/ { SPR_GRIN, 1, 3, { A_MissileTick }, S_GRIN_00 }, //184
+/*S_GRAP_00*/ { SPR_GRAP, 0, 3, { A_MissileTick }, S_GRAP_01 }, //185
+/*S_GRAP_01*/ { SPR_GRAP, 1, 3, { A_MissileTick }, S_GRAP_00 }, //186
+/*S_UBAM_00*/ { SPR_UBAM, 0, 3, { A_MissileTick }, S_UBAM_01 }, //187
+/*S_UBAM_01*/ { SPR_UBAM, 1, 3, { A_MissileTick }, S_UBAM_00 }, //188
+/*S_BNG2_00*/ { SPR_BNG2, 32768, 4, { A_DeathExplode5 }, S_BNG2_01 }, //189
+/*S_BNG2_01*/ { SPR_BNG2, 32769, 4, { NULL }, S_BNG2_02 }, //190
+/*S_BNG2_02*/ { SPR_BNG2, 32770, 4, { NULL }, S_BNG2_03 }, //191
+/*S_BNG2_03*/ { SPR_BNG2, 32771, 4, { NULL }, S_BNG2_04 }, //192
+/*S_BNG2_04*/ { SPR_BNG2, 32772, 4, { NULL }, S_BNG2_05 }, //193
+/*S_BNG2_05*/ { SPR_BNG2, 32773, 4, { NULL }, S_BNG2_06 }, //194
+/*S_BNG2_06*/ { SPR_BNG2, 32774, 4, { NULL }, S_BNG2_07 }, //195
+/*S_BNG2_07*/ { SPR_BNG2, 32775, 4, { NULL }, S_BNG2_08 }, //196
+/*S_BNG2_08*/ { SPR_BNG2, 32776, 4, { NULL }, S_NULL }, //197
+/*S_BNG4_00*/ { SPR_BNG4, 32768, 2, { A_DeathExplode5 }, S_BNG4_01 }, //198
+/*S_BNG4_01*/ { SPR_BNG4, 32769, 3, { NULL }, S_BNG4_02 }, //199
+/*S_BNG4_02*/ { SPR_BNG4, 32770, 3, { NULL }, S_BNG4_03 }, //200
+/*S_BNG4_03*/ { SPR_BNG4, 32771, 3, { NULL }, S_BNG4_04 }, //201
+/*S_BNG4_04*/ { SPR_BNG4, 32772, 3, { NULL }, S_BNG4_05 }, //202
+/*S_BNG4_05*/ { SPR_BNG4, 32773, 3, { NULL }, S_BNG4_06 }, //203
+/*S_BNG4_06*/ { SPR_BNG4, 32774, 3, { NULL }, S_BNG4_07 }, //204
+/*S_BNG4_07*/ { SPR_BNG4, 32775, 3, { NULL }, S_BNG4_08 }, //205
+/*S_BNG4_08*/ { SPR_BNG4, 32776, 3, { NULL }, S_BNG4_09 }, //206
+/*S_BNG4_09*/ { SPR_BNG4, 32777, 3, { NULL }, S_BNG4_10 }, //207
+/*S_BNG4_10*/ { SPR_BNG4, 32778, 3, { NULL }, S_BNG4_11 }, //208
+/*S_BNG4_11*/ { SPR_BNG4, 32779, 3, { NULL }, S_BNG4_12 }, //209
+/*S_BNG4_12*/ { SPR_BNG4, 32780, 3, { NULL }, S_BNG4_13 }, //210
+/*S_BNG4_13*/ { SPR_BNG4, 32781, 3, { NULL }, S_NULL }, //211
+/*S_BNG3_00*/ { SPR_BNG3, 32768, 3, { A_DeathExplode5 }, S_BNG3_01 }, //212
+/*S_BNG3_01*/ { SPR_BNG3, 32769, 3, { NULL }, S_BNG3_02 }, //213
+/*S_BNG3_02*/ { SPR_BNG3, 32770, 3, { NULL }, S_BNG3_03 }, //214
+/*S_BNG3_03*/ { SPR_BNG3, 32771, 3, { NULL }, S_BNG3_04 }, //215
+/*S_BNG3_04*/ { SPR_BNG3, 32772, 3, { NULL }, S_BNG3_05 }, //216
+/*S_BNG3_05*/ { SPR_BNG3, 32773, 3, { NULL }, S_BNG3_06 }, //217
+/*S_BNG3_06*/ { SPR_BNG3, 32774, 3, { NULL }, S_BNG3_07 }, //218
+/*S_BNG3_07*/ { SPR_BNG3, 32775, 3, { NULL }, S_NULL }, //219
+/*S_BNG3_08*/ { SPR_BNG3, 0, 1, { A_SpawnGrenadeFire }, S_NULL }, //220
+/*S_BNG3_09*/ { SPR_BNG3, 32769, 2, { A_DeathExplode1 }, S_BNG3_10 }, //221
+/*S_BNG3_10*/ { SPR_BNG3, 32770, 2, { A_MissileTick }, S_FLBE_00 }, //222
+/*S_FLBE_00*/ { SPR_FLBE, 32768, 2, { A_BurnSpread }, S_FLBE_01 }, //223
+/*S_FLBE_01*/ { SPR_FLBE, 32769, 2, { A_MissileTick }, S_FLBE_02 }, //224
+/*S_FLBE_02*/ { SPR_FLBE, 32770, 2, { A_DeathExplode1 }, S_FLBE_03 }, //225
+/*S_FLBE_03*/ { SPR_FLBE, 32771, 3, { A_MissileTick }, S_FLBE_04 }, //226
+/*S_FLBE_04*/ { SPR_FLBE, 32772, 3, { A_DeathExplode1 }, S_FLBE_05 }, //227
+/*S_FLBE_05*/ { SPR_FLBE, 32773, 3, { A_MissileTick }, S_FLBE_06 }, //228
+/*S_FLBE_06*/ { SPR_FLBE, 32774, 3, { A_BurnSpread }, S_FLBE_03 }, //229
+/*S_FLBE_07*/ { SPR_FLBE, 32775, 2, { NULL }, S_FLBE_08 }, //230
+/*S_FLBE_08*/ { SPR_FLBE, 32776, 2, { A_BurnSpread }, S_FLBE_09 }, //231
+/*S_FLBE_09*/ { SPR_FLBE, 32777, 2, { NULL }, S_FLBE_10 }, //232
+/*S_FLBE_10*/ { SPR_FLBE, 32778, 2, { NULL }, S_NULL }, //233
+/*S_XPRK_00*/ { SPR_XPRK, 0, 1, { A_ClearForceField }, S_NULL }, //234
+/*S_OCLW_00*/ { SPR_OCLW, 0, 2, { A_FireChainShot }, S_OCLW_00 }, //235
+/*S_CCLW_00*/ { SPR_CCLW, 0, 6, { NULL }, S_NULL }, //236
+/*S_TEND_00*/ { SPR_TEND, 0, 20, { NULL }, S_NULL }, //237
+/*S_MICR_00*/ { SPR_MICR, 32768, 6, { A_MissileSmoke }, S_MICR_00 }, //238
+/*S_MISS_00*/ { SPR_MISS, 32768, 4, { A_MissileSmoke }, S_MISS_01 }, //239
+/*S_MISS_01*/ { SPR_MISS, 32769, 3, { A_Tracer }, S_MISS_00 }, //240
+/*S_AROW_00*/ { SPR_AROW, 0, 10, { A_ActiveSound }, S_AROW_00 }, //241
+/*S_ARWP_00*/ { SPR_ARWP, 0, 10, { A_ActiveSound }, S_ARWP_00 }, //242
+/*S_AROW_01*/ { SPR_AROW, 0, 1, { NULL }, S_NULL }, //243
+/*S_TORP_00*/ { SPR_TORP, 32768, 4, { NULL }, S_TORP_01 }, //244
+/*S_TORP_01*/ { SPR_TORP, 32769, 4, { NULL }, S_TORP_02 }, //245
+/*S_TORP_02*/ { SPR_TORP, 32770, 4, { NULL }, S_TORP_03 }, //246
+/*S_TORP_03*/ { SPR_TORP, 32771, 4, { NULL }, S_TORP_00 }, //247
+/*S_THIT_00*/ { SPR_THIT, 32768, 8, { NULL }, S_THIT_01 }, //248
+/*S_THIT_01*/ { SPR_THIT, 32769, 8, { NULL }, S_THIT_02 }, //249
+/*S_THIT_02*/ { SPR_THIT, 32770, 8, { A_TorpedoExplode }, S_THIT_03 }, //250
+/*S_THIT_03*/ { SPR_THIT, 32771, 8, { NULL }, S_THIT_04 }, //251
+/*S_THIT_04*/ { SPR_THIT, 32772, 8, { NULL }, S_NULL }, //252
+/*S_TWAV_00*/ { SPR_TWAV, 32768, 9, { NULL }, S_TWAV_01 }, //253
+/*S_TWAV_01*/ { SPR_TWAV, 32769, 9, { NULL }, S_TWAV_02 }, //254
+/*S_TWAV_02*/ { SPR_TWAV, 32770, 9, { NULL }, S_NULL }, //255
+/*S_MISL_00*/ { SPR_MISL, 32768, 5, { NULL }, S_MISL_02 }, //256
+/*S_MISL_01*/ { SPR_MISL, 32768, 5, { A_DeathExplode2 }, S_MISL_02 }, //257
+/*S_MISL_02*/ { SPR_MISL, 32769, 5, { NULL }, S_MISL_03 }, //258
+/*S_MISL_03*/ { SPR_MISL, 32770, 4, { NULL }, S_MISL_04 }, //259
+/*S_MISL_04*/ { SPR_MISL, 32771, 2, { NULL }, S_MISL_05 }, //260
+/*S_MISL_05*/ { SPR_MISL, 32772, 2, { NULL }, S_MISL_06 }, //261
+/*S_MISL_06*/ { SPR_MISL, 32773, 2, { NULL }, S_MISL_07 }, //262
+/*S_MISL_07*/ { SPR_MISL, 32774, 2, { NULL }, S_NULL }, //263
+/*S_TFOG_00*/ { SPR_TFOG, 32768, 6, { NULL }, S_TFOG_01 }, //264
+/*S_TFOG_01*/ { SPR_TFOG, 32769, 6, { NULL }, S_TFOG_02 }, //265
+/*S_TFOG_02*/ { SPR_TFOG, 32770, 6, { NULL }, S_TFOG_03 }, //266
+/*S_TFOG_03*/ { SPR_TFOG, 32771, 6, { NULL }, S_TFOG_04 }, //267
+/*S_TFOG_04*/ { SPR_TFOG, 32772, 6, { NULL }, S_TFOG_05 }, //268
+/*S_TFOG_05*/ { SPR_TFOG, 32773, 6, { NULL }, S_TFOG_06 }, //269
+/*S_TFOG_06*/ { SPR_TFOG, 32772, 6, { NULL }, S_TFOG_07 }, //270
+/*S_TFOG_07*/ { SPR_TFOG, 32771, 6, { NULL }, S_TFOG_08 }, //271
+/*S_TFOG_08*/ { SPR_TFOG, 32770, 6, { NULL }, S_TFOG_09 }, //272
+/*S_TFOG_09*/ { SPR_TFOG, 32769, 6, { NULL }, S_NULL }, //273
+/*S_IFOG_00*/ { SPR_IFOG, 32768, 6, { NULL }, S_IFOG_01 }, //274
+/*S_IFOG_01*/ { SPR_IFOG, 32769, 6, { NULL }, S_IFOG_02 }, //275
+/*S_IFOG_02*/ { SPR_IFOG, 32768, 6, { NULL }, S_IFOG_03 }, //276
+/*S_IFOG_03*/ { SPR_IFOG, 32769, 6, { NULL }, S_IFOG_04 }, //277
+/*S_IFOG_04*/ { SPR_IFOG, 32770, 6, { NULL }, S_IFOG_05 }, //278
+/*S_IFOG_05*/ { SPR_IFOG, 32771, 6, { NULL }, S_IFOG_06 }, //279
+/*S_IFOG_06*/ { SPR_IFOG, 32772, 6, { NULL }, S_NULL }, //280
+/*S_SHRD_00*/ { SPR_SHRD, 0, 128, { NULL }, S_NULL }, //281
+/*S_SHRD_01*/ { SPR_SHRD, 1, 128, { NULL }, S_NULL }, //282
+/*S_SHRD_02*/ { SPR_SHRD, 2, 128, { NULL }, S_NULL }, //283
+/*S_SHRD_03*/ { SPR_SHRD, 3, 128, { NULL }, S_NULL }, //284
+/*S_SHRD_04*/ { SPR_SHRD, 4, 128, { NULL }, S_NULL }, //285
+/*S_SHRD_05*/ { SPR_SHRD, 5, 128, { NULL }, S_NULL }, //286
+/*S_PLAY_00*/ { SPR_PLAY, 0, -1, { NULL }, S_NULL }, //287
+/*S_PLAY_01*/ { SPR_PLAY, 0, 4, { NULL }, S_PLAY_02 }, //288
+/*S_PLAY_02*/ { SPR_PLAY, 1, 4, { NULL }, S_PLAY_03 }, //289
+/*S_PLAY_03*/ { SPR_PLAY, 2, 4, { NULL }, S_PLAY_04 }, //290
+/*S_PLAY_04*/ { SPR_PLAY, 3, 4, { NULL }, S_PLAY_01 }, //291
+/*S_PLAY_05*/ { SPR_PLAY, 4, 12, { NULL }, S_PLAY_00 }, //292
+/*S_PLAY_06*/ { SPR_PLAY, 5, 6, { NULL }, S_PLAY_05 }, //293
+/*S_PLAY_07*/ { SPR_PLAY, 16, 4, { A_Pain }, S_PLAY_08 }, //294
+/*S_PLAY_08*/ { SPR_PLAY, 16, 4, { NULL }, S_PLAY_00 }, //295
+/*S_PLAY_09*/ { SPR_PLAY, 6, 4, { NULL }, S_PLAY_10 }, //296
+/*S_PLAY_10*/ { SPR_PLAY, 7, 3, { A_PlayerScream }, S_PLAY_11 }, //297
+/*S_PLAY_11*/ { SPR_PLAY, 8, 3, { A_Fall }, S_PLAY_12 }, //298
+/*S_PLAY_12*/ { SPR_PLAY, 9, 4, { NULL }, S_PLAY_13 }, //299
+/*S_PLAY_13*/ { SPR_PLAY, 10, 4, { NULL }, S_PLAY_14 }, //300
+/*S_PLAY_14*/ { SPR_PLAY, 11, 4, { NULL }, S_PLAY_15 }, //301
+/*S_PLAY_15*/ { SPR_PLAY, 12, 4, { NULL }, S_PLAY_16 }, //302
+/*S_PLAY_16*/ { SPR_PLAY, 13, 4, { NULL }, S_PLAY_17 }, //303
+/*S_PLAY_17*/ { SPR_PLAY, 14, 4, { NULL }, S_PLAY_18 }, //304
+/*S_PLAY_18*/ { SPR_PLAY, 15, 700, { NULL }, S_RGIB_07 }, //305
+/*S_RGIB_00*/ { SPR_RGIB, 0, 5, { A_BodyParts }, S_RGIB_01 }, //306
+/*S_RGIB_01*/ { SPR_RGIB, 1, 5, { A_XScream }, S_RGIB_02 }, //307
+/*S_RGIB_02*/ { SPR_RGIB, 2, 5, { A_Fall }, S_RGIB_03 }, //308
+/*S_RGIB_03*/ { SPR_RGIB, 3, 5, { A_BodyParts }, S_RGIB_04 }, //309
+/*S_RGIB_04*/ { SPR_RGIB, 4, 5, { A_BodyParts }, S_RGIB_05 }, //310
+/*S_RGIB_05*/ { SPR_RGIB, 5, 5, { A_BodyParts }, S_RGIB_06 }, //311
+/*S_RGIB_06*/ { SPR_RGIB, 6, 5, { A_BodyParts }, S_RGIB_07 }, //312
+/*S_RGIB_07*/ { SPR_RGIB, 7, 1400, { NULL }, S_NULL }, //313
+/*S_MRYS_00*/ { SPR_MRYS, 0, 30, { NULL }, S_MRST_00 }, //314
+/*S_MRNO_00*/ { SPR_MRNO, 0, 6, { NULL }, S_MRNO_01 }, //315
+/*S_MRNO_01*/ { SPR_MRNO, 1, 6, { NULL }, S_MRNO_02 }, //316
+/*S_MRNO_02*/ { SPR_MRNO, 2, 10, { NULL }, S_MRNO_03 }, //317
+/*S_MRNO_03*/ { SPR_MRNO, 1, 6, { NULL }, S_MRNO_04 }, //318
+/*S_MRNO_04*/ { SPR_MRNO, 0, 6, { NULL }, S_MRST_00 }, //319
+/*S_MRST_00*/ { SPR_MRST, 0, 10, { A_FriendLook }, S_MRST_00 }, //320
+/*S_MRLK_00*/ { SPR_MRLK, 0, 30, { A_ActiveSound }, S_MRST_00 }, //321
+/*S_MRLK_01*/ { SPR_MRLK, 1, 30, { NULL }, S_MRST_00 }, //322
+/*S_MRBD_00*/ { SPR_MRBD, 0, 4, { NULL }, S_MRBD_01 }, //323
+/*S_MRBD_01*/ { SPR_MRBD, 1, 4, { NULL }, S_MRBD_02 }, //324
+/*S_MRBD_02*/ { SPR_MRBD, 2, 4, { NULL }, S_MRBD_03 }, //325
+/*S_MRBD_03*/ { SPR_MRBD, 3, 4, { NULL }, S_MRBD_04 }, //326
+/*S_MRBD_04*/ { SPR_MRBD, 4, 4, { NULL }, S_MRBD_05 }, //327
+/*S_MRBD_05*/ { SPR_MRBD, 3, 4, { NULL }, S_MRBD_06 }, //328
+/*S_MRBD_06*/ { SPR_MRBD, 2, 4, { NULL }, S_MRBD_07 }, //329
+/*S_MRBD_07*/ { SPR_MRBD, 1, 4, { NULL }, S_MRBD_08 }, //330
+/*S_MRBD_08*/ { SPR_MRBD, 0, 5, { NULL }, S_MRBD_09 }, //331
+/*S_MRBD_09*/ { SPR_MRBD, 5, 6, { NULL }, S_MRST_00 }, //332
+/*S_MRPN_00*/ { SPR_MRPN, 0, 3, { NULL }, S_MRPN_01 }, //333
+/*S_MRPN_01*/ { SPR_MRPN, 1, 3, { A_Pain }, S_MRPN_02 }, //334
+/*S_MRPN_02*/ { SPR_MRPN, 2, 3, { NULL }, S_MRPN_03 }, //335
+/*S_MRPN_03*/ { SPR_MRPN, 3, 9, { A_MerchantPain }, S_MRPN_04 }, //336
+/*S_MRPN_04*/ { SPR_MRPN, 2, 4, { NULL }, S_MRPN_05 }, //337
+/*S_MRPN_05*/ { SPR_MRPN, 1, 3, { NULL }, S_MRPN_06 }, //338
+/*S_MRPN_06*/ { SPR_MRPN, 0, 3, { A_ClearSoundTarget }, S_MRST_00 }, //339
+/*S_MRGT_00*/ { SPR_MRGT, 0, 5, { NULL }, S_MRGT_01 }, //340
+/*S_MRGT_01*/ { SPR_MRGT, 1, 5, { NULL }, S_MRGT_02 }, //341
+/*S_MRGT_02*/ { SPR_MRGT, 2, 5, { NULL }, S_MRGT_03 }, //342
+/*S_MRGT_03*/ { SPR_MRGT, 3, 5, { NULL }, S_MRGT_04 }, //343
+/*S_MRGT_04*/ { SPR_MRGT, 4, 5, { NULL }, S_MRGT_05 }, //344
+/*S_MRGT_05*/ { SPR_MRGT, 5, 5, { NULL }, S_MRGT_06 }, //345
+/*S_MRGT_06*/ { SPR_MRGT, 6, 5, { NULL }, S_MRGT_07 }, //346
+/*S_MRGT_07*/ { SPR_MRGT, 7, 5, { NULL }, S_MRGT_08 }, //347
+/*S_MRGT_08*/ { SPR_MRGT, 8, 5, { NULL }, S_MRST_00 }, //348
+/*S_BURN_00*/ { SPR_BURN, 0, 3, { A_Scream }, S_BURN_01 }, //349
+/*S_BURN_01*/ { SPR_BURN, 1, 3, { A_DropBurnFlesh }, S_BURN_02 }, //350
+/*S_BURN_02*/ { SPR_BURN, 2, 3, { A_RandomWalk }, S_BURN_03 }, //351
+/*S_BURN_03*/ { SPR_BURN, 3, 3, { A_Fall }, S_BURN_04 }, //352
+/*S_BURN_04*/ { SPR_BURN, 4, 5, { A_DropBurnFlesh }, S_BURN_05 }, //353
+/*S_BURN_05*/ { SPR_BURN, 5, 5, { A_RandomWalk }, S_BURN_06 }, //354
+/*S_BURN_06*/ { SPR_BURN, 6, 5, { A_RandomWalk }, S_BURN_07 }, //355
+/*S_BURN_07*/ { SPR_BURN, 7, 5, { A_RandomWalk }, S_BURN_08 }, //356
+/*S_BURN_08*/ { SPR_BURN, 8, 5, { A_DropBurnFlesh }, S_BURN_09 }, //357
+/*S_BURN_09*/ { SPR_BURN, 9, 5, { A_RandomWalk }, S_BURN_10 }, //358
+/*S_BURN_10*/ { SPR_BURN, 10, 5, { A_RandomWalk }, S_BURN_11 }, //359
+/*S_BURN_11*/ { SPR_BURN, 11, 5, { A_RandomWalk }, S_BURN_12 }, //360
+/*S_BURN_12*/ { SPR_BURN, 12, 3, { A_DropBurnFlesh }, S_BURN_13 }, //361
+/*S_BURN_13*/ { SPR_BURN, 13, 3, { NULL }, S_BURN_14 }, //362
+/*S_BURN_14*/ { SPR_BURN, 14, 5, { NULL }, S_BURN_15 }, //363
+/*S_BURN_15*/ { SPR_BURN, 15, 5, { NULL }, S_BURN_16 }, //364
+/*S_BURN_16*/ { SPR_BURN, 16, 5, { NULL }, S_BURN_17 }, //365
+/*S_BURN_17*/ { SPR_BURN, 15, 5, { NULL }, S_BURN_18 }, //366
+/*S_BURN_18*/ { SPR_BURN, 16, 5, { NULL }, S_BURN_19 }, //367
+/*S_BURN_19*/ { SPR_BURN, 17, 7, { NULL }, S_BURN_20 }, //368
+/*S_BURN_20*/ { SPR_BURN, 18, 7, { NULL }, S_BURN_21 }, //369
+/*S_BURN_21*/ { SPR_BURN, 19, 7, { NULL }, S_BURN_22 }, //370
+/*S_BURN_22*/ { SPR_BURN, 20, 7, { NULL }, S_BURN_23 }, //371
+/*S_BURN_23*/ { SPR_BURN, 21, 700, { A_PeasantCrash }, S_NULL }, //372
+/*S_DISR_00*/ { SPR_DISR, 0, 5, { NULL }, S_DISR_01 }, //373
+/*S_DISR_01*/ { SPR_DISR, 1, 5, { NULL }, S_DISR_02 }, //374
+/*S_DISR_02*/ { SPR_DISR, 2, 5, { NULL }, S_DISR_03 }, //375
+/*S_DISR_03*/ { SPR_DISR, 3, 5, { A_Fall }, S_DISR_04 }, //376
+/*S_DISR_04*/ { SPR_DISR, 4, 5, { NULL }, S_DISR_05 }, //377
+/*S_DISR_05*/ { SPR_DISR, 5, 5, { NULL }, S_DISR_06 }, //378
+/*S_DISR_06*/ { SPR_DISR, 6, 4, { NULL }, S_DISR_07 }, //379
+/*S_DISR_07*/ { SPR_DISR, 7, 4, { NULL }, S_DISR_08 }, //380
+/*S_DISR_08*/ { SPR_DISR, 8, 4, { NULL }, S_DISR_09 }, //381
+/*S_DISR_09*/ { SPR_DISR, 9, 4, { NULL }, S_MEAT_03 }, //382
+/*S_PEAS_00*/ { SPR_PEAS, 0, 10, { A_FriendLook }, S_PEAS_00 }, //383
+/*S_PEAS_01*/ { SPR_PEAS, 0, 5, { A_RandomWalk }, S_PEAS_02 }, //384
+/*S_PEAS_02*/ { SPR_PEAS, 0, 5, { A_RandomWalk }, S_PEAS_03 }, //385
+/*S_PEAS_03*/ { SPR_PEAS, 1, 5, { A_RandomWalk }, S_PEAS_04 }, //386
+/*S_PEAS_04*/ { SPR_PEAS, 1, 5, { A_RandomWalk }, S_PEAS_05 }, //387
+/*S_PEAS_05*/ { SPR_PEAS, 2, 5, { A_RandomWalk }, S_PEAS_06 }, //388
+/*S_PEAS_06*/ { SPR_PEAS, 2, 5, { A_RandomWalk }, S_PEAS_07 }, //389
+/*S_PEAS_07*/ { SPR_PEAS, 3, 5, { A_RandomWalk }, S_PEAS_08 }, //390
+/*S_PEAS_08*/ { SPR_PEAS, 3, 5, { A_RandomWalk }, S_PEAS_00 }, //391
+/*S_PEAS_09*/ { SPR_PEAS, 4, 10, { A_FaceTarget }, S_PEAS_10 }, //392
+/*S_PEAS_10*/ { SPR_PEAS, 5, 8, { A_PeasantPunch }, S_PEAS_11 }, //393
+/*S_PEAS_11*/ { SPR_PEAS, 4, 8, { NULL }, S_PEAS_01 }, //394
+/*S_PEAS_12*/ { SPR_PEAS, 14, 3, { NULL }, S_PEAS_13 }, //395
+/*S_PEAS_13*/ { SPR_PEAS, 14, 3, { A_Pain }, S_PEAS_09 }, //396
+/*S_PEAS_14*/ { SPR_PEAS, 6, 5, { NULL }, S_PEAS_15 }, //397
+/*S_PEAS_15*/ { SPR_PEAS, 7, 10, { A_PeasantCrash }, S_PEAS_16 }, //398
+/*S_PEAS_16*/ { SPR_PEAS, 8, 6, { NULL }, S_PEAS_15 }, //399
+/*S_PEAS_17*/ { SPR_PEAS, 6, 5, { NULL }, S_PEAS_18 }, //400
+/*S_PEAS_18*/ { SPR_PEAS, 7, 5, { A_Scream }, S_PEAS_19 }, //401
+/*S_PEAS_19*/ { SPR_PEAS, 8, 6, { NULL }, S_PEAS_20 }, //402
+/*S_PEAS_20*/ { SPR_PEAS, 9, 5, { A_Fall }, S_PEAS_21 }, //403
+/*S_PEAS_21*/ { SPR_PEAS, 10, 5, { NULL }, S_PEAS_22 }, //404
+/*S_PEAS_22*/ { SPR_PEAS, 11, 6, { NULL }, S_PEAS_23 }, //405
+/*S_PEAS_23*/ { SPR_PEAS, 12, 8, { NULL }, S_PEAS_24 }, //406
+/*S_PEAS_24*/ { SPR_PEAS, 13, 1400, { NULL }, S_GIBS_08 }, //407
+/*S_GIBS_00*/ { SPR_GIBS, 12, 5, { A_BodyParts }, S_GIBS_01 }, //408
+/*S_GIBS_01*/ { SPR_GIBS, 13, 5, { A_XScream }, S_GIBS_02 }, //409
+/*S_GIBS_02*/ { SPR_GIBS, 14, 5, { A_Fall }, S_GIBS_03 }, //410
+/*S_GIBS_03*/ { SPR_GIBS, 15, 4, { A_BodyParts }, S_GIBS_04 }, //411
+/*S_GIBS_04*/ { SPR_GIBS, 16, 4, { A_BodyParts }, S_GIBS_05 }, //412
+/*S_GIBS_05*/ { SPR_GIBS, 17, 4, { A_BodyParts }, S_GIBS_06 }, //413
+/*S_GIBS_06*/ { SPR_GIBS, 18, 4, { A_BodyParts }, S_GIBS_07 }, //414
+/*S_GIBS_07*/ { SPR_GIBS, 19, 4, { NULL }, S_GIBS_08 }, //415
+/*S_GIBS_08*/ { SPR_GIBS, 20, 5, { NULL }, S_GIBS_09 }, //416
+/*S_GIBS_09*/ { SPR_GIBS, 21, 1400, { NULL }, S_NULL }, //417
+/*S_PEAS_25*/ { SPR_PEAS, 0, 5, { A_ZombieInSpecialSector }, S_PEAS_25 }, //418
+/*S_AGRD_00*/ { SPR_AGRD, 0, 5, { A_ZombieInSpecialSector }, S_AGRD_00 }, //419
+/*S_ARMR_00*/ { SPR_ARMR, 0, -1, { NULL }, S_NULL }, //420
+/*S_ARMR_01*/ { SPR_ARMR, 0, -1, { A_HideZombie }, S_NULL }, //421
+/*S_PLAY_19*/ { SPR_PLAY, 0, 175, { A_SpawnZombie }, S_PLAY_19 }, //422
+/*S_SACR_00*/ { SPR_SACR, 0, -1, { NULL }, S_NULL }, //423
+/*S_TNK1_00*/ { SPR_TNK1, 0, 15, { NULL }, S_TNK1_01 }, //424
+/*S_TNK1_01*/ { SPR_TNK1, 1, 11, { NULL }, S_TNK1_02 }, //425
+/*S_TNK1_02*/ { SPR_TNK1, 2, 40, { NULL }, S_TNK1_00 }, //426
+/*S_TNK2_00*/ { SPR_TNK2, 0, 15, { NULL }, S_TNK2_01 }, //427
+/*S_TNK2_01*/ { SPR_TNK2, 1, 11, { NULL }, S_TNK2_02 }, //428
+/*S_TNK2_02*/ { SPR_TNK2, 2, 40, { NULL }, S_TNK2_00 }, //429
+/*S_TNK3_00*/ { SPR_TNK3, 0, 15, { NULL }, S_TNK3_01 }, //430
+/*S_TNK3_01*/ { SPR_TNK3, 1, 11, { NULL }, S_TNK3_02 }, //431
+/*S_TNK3_02*/ { SPR_TNK3, 2, 40, { NULL }, S_TNK3_00 }, //432
+/*S_TNK4_00*/ { SPR_TNK4, 0, 15, { NULL }, S_TNK4_01 }, //433
+/*S_TNK4_01*/ { SPR_TNK4, 1, 11, { NULL }, S_TNK4_02 }, //434
+/*S_TNK4_02*/ { SPR_TNK4, 2, 40, { NULL }, S_TNK4_00 }, //435
+/*S_TNK5_00*/ { SPR_TNK5, 0, 15, { NULL }, S_TNK5_01 }, //436
+/*S_TNK5_01*/ { SPR_TNK5, 1, 11, { NULL }, S_TNK5_02 }, //437
+/*S_TNK5_02*/ { SPR_TNK5, 2, 40, { NULL }, S_TNK5_00 }, //438
+/*S_TNK6_00*/ { SPR_TNK6, 0, 15, { NULL }, S_TNK6_01 }, //439
+/*S_TNK6_01*/ { SPR_TNK6, 1, 11, { NULL }, S_TNK6_02 }, //440
+/*S_TNK6_02*/ { SPR_TNK6, 2, 40, { NULL }, S_TNK6_00 }, //441
+/*S_NEAL_00*/ { SPR_NEAL, 0, 15, { A_ActiveSound }, S_NEAL_01 }, //442
+/*S_NEAL_01*/ { SPR_NEAL, 1, 40, { A_ActiveSound }, S_NEAL_00 }, //443
+/*S_NEAL_02*/ { SPR_NEAL, 2, 5, { A_ShadowOn }, S_NEAL_03 }, //444
+/*S_NEAL_03*/ { SPR_NEAL, 1, 4, { A_Pain }, S_NEAL_04 }, //445
+/*S_NEAL_04*/ { SPR_NEAL, 2, 5, { A_ShadowOff }, S_NEAL_00 }, //446
+/*S_NEAL_05*/ { SPR_NEAL, 1, 6, { NULL }, S_NEAL_06 }, //447
+/*S_NEAL_06*/ { SPR_NEAL, 2, 13, { A_PeasantCrash }, S_NEAL_05 }, //448
+/*S_NEAL_07*/ { SPR_NEAL, 3, 5, { NULL }, S_NEAL_08 }, //449
+/*S_NEAL_08*/ { SPR_NEAL, 4, 5, { A_Scream }, S_NEAL_09 }, //450
+/*S_NEAL_09*/ { SPR_NEAL, 5, 6, { NULL }, S_NEAL_10 }, //451
+/*S_NEAL_10*/ { SPR_NEAL, 6, 5, { A_Fall }, S_NEAL_11 }, //452
+/*S_NEAL_11*/ { SPR_NEAL, 7, 5, { NULL }, S_NEAL_12 }, //453
+/*S_NEAL_12*/ { SPR_NEAL, 8, 6, { NULL }, S_NEAL_13 }, //454
+/*S_NEAL_13*/ { SPR_NEAL, 9, -1, { NULL }, S_NULL }, //455
+/*S_BEGR_00*/ { SPR_BEGR, 0, 10, { A_Look }, S_BEGR_00 }, //456
+/*S_BEGR_01*/ { SPR_BEGR, 0, 4, { A_RandomWalk }, S_BEGR_02 }, //457
+/*S_BEGR_02*/ { SPR_BEGR, 0, 4, { A_RandomWalk }, S_BEGR_03 }, //458
+/*S_BEGR_03*/ { SPR_BEGR, 1, 4, { A_RandomWalk }, S_BEGR_04 }, //459
+/*S_BEGR_04*/ { SPR_BEGR, 1, 4, { A_RandomWalk }, S_BEGR_05 }, //460
+/*S_BEGR_05*/ { SPR_BEGR, 2, 4, { A_RandomWalk }, S_BEGR_06 }, //461
+/*S_BEGR_06*/ { SPR_BEGR, 2, 4, { A_RandomWalk }, S_BEGR_01 }, //462
+/*S_BEGR_07*/ { SPR_BEGR, 3, 8, { NULL }, S_BEGR_08 }, //463
+/*S_BEGR_08*/ { SPR_BEGR, 4, 8, { A_PeasantPunch }, S_BEGR_09 }, //464
+/*S_BEGR_09*/ { SPR_BEGR, 4, 1, { A_Chase }, S_BEGR_10 }, //465
+/*S_BEGR_10*/ { SPR_BEGR, 3, 8, { A_CheckTargetVisible }, S_BEGR_07 }, //466
+/*S_BEGR_11*/ { SPR_BEGR, 0, 3, { A_Pain }, S_BEGR_12 }, //467
+/*S_BEGR_12*/ { SPR_BEGR, 0, 3, { A_Chase }, S_BEGR_07 }, //468
+/*S_BEGR_13*/ { SPR_BEGR, 5, 4, { NULL }, S_BEGR_14 }, //469
+/*S_BEGR_14*/ { SPR_BEGR, 6, 4, { A_Scream }, S_BEGR_15 }, //470
+/*S_BEGR_15*/ { SPR_BEGR, 7, 4, { NULL }, S_BEGR_16 }, //471
+/*S_BEGR_16*/ { SPR_BEGR, 8, 4, { A_Fall }, S_BEGR_17 }, //472
+/*S_BEGR_17*/ { SPR_BEGR, 9, 4, { NULL }, S_BEGR_18 }, //473
+/*S_BEGR_18*/ { SPR_BEGR, 10, 4, { NULL }, S_BEGR_19 }, //474
+/*S_BEGR_19*/ { SPR_BEGR, 11, 4, { NULL }, S_BEGR_20 }, //475
+/*S_BEGR_20*/ { SPR_BEGR, 12, 4, { NULL }, S_BEGR_21 }, //476
+/*S_BEGR_21*/ { SPR_BEGR, 13, -1, { NULL }, S_NULL }, //477
+/*S_BEGR_22*/ { SPR_BEGR, 5, 5, { A_BodyParts }, S_GIBS_01 }, //478
+/*S_HMN1_00*/ { SPR_HMN1, 15, 5, { A_FriendLook }, S_HMN1_00 }, //479
+/*S_HMN1_01*/ { SPR_HMN1, 16, 8, { NULL }, S_HMN1_00 }, //480
+/*S_HMN1_02*/ { SPR_HMN1, 17, 8, { NULL }, S_HMN1_00 }, //481
+/*S_HMN1_03*/ { SPR_HMN1, 0, 6, { A_RandomWalk }, S_HMN1_04 }, //482
+/*S_HMN1_04*/ { SPR_HMN1, 1, 6, { A_RandomWalk }, S_HMN1_05 }, //483
+/*S_HMN1_05*/ { SPR_HMN1, 2, 6, { A_RandomWalk }, S_HMN1_06 }, //484
+/*S_HMN1_06*/ { SPR_HMN1, 3, 6, { A_RandomWalk }, S_HMN1_07 }, //485
+/*S_HMN1_07*/ { SPR_HMN1, 0, 6, { A_RandomWalk }, S_HMN1_08 }, //486
+/*S_HMN1_08*/ { SPR_HMN1, 1, 6, { A_RandomWalk }, S_HMN1_09 }, //487
+/*S_HMN1_09*/ { SPR_HMN1, 2, 6, { A_RandomWalk }, S_HMN1_10 }, //488
+/*S_HMN1_10*/ { SPR_HMN1, 3, 6, { A_RandomWalk }, S_HMN1_00 }, //489
+/*S_HMN1_11*/ { SPR_HMN1, 0, 3, { A_Chase }, S_HMN1_12 }, //490
+/*S_HMN1_12*/ { SPR_HMN1, 0, 3, { A_Chase }, S_HMN1_13 }, //491
+/*S_HMN1_13*/ { SPR_HMN1, 1, 3, { A_Chase }, S_HMN1_14 }, //492
+/*S_HMN1_14*/ { SPR_HMN1, 1, 3, { A_Chase }, S_HMN1_15 }, //493
+/*S_HMN1_15*/ { SPR_HMN1, 2, 3, { A_Chase }, S_HMN1_16 }, //494
+/*S_HMN1_16*/ { SPR_HMN1, 2, 3, { A_Chase }, S_HMN1_17 }, //495
+/*S_HMN1_17*/ { SPR_HMN1, 3, 3, { A_Chase }, S_HMN1_18 }, //496
+/*S_HMN1_18*/ { SPR_HMN1, 3, 3, { A_Chase }, S_HMN1_11 }, //497
+/*S_HMN1_19*/ { SPR_HMN1, 4, 10, { A_FaceTarget }, S_HMN1_20 }, //498
+/*S_HMN1_20*/ { SPR_HMN1, 32773, 10, { A_BulletAttack }, S_HMN1_21 }, //499
+/*S_HMN1_21*/ { SPR_HMN1, 4, 10, { A_BulletAttack }, S_HMN1_11 }, //500
+/*S_HMN1_22*/ { SPR_HMN1, 14, 3, { NULL }, S_HMN1_23 }, //501
+/*S_HMN1_23*/ { SPR_HMN1, 14, 3, { A_Pain }, S_HMN1_11 }, //502
+/*S_HMN1_24*/ { SPR_HMN1, 6, 5, { NULL }, S_HMN1_25 }, //503
+/*S_HMN1_25*/ { SPR_HMN1, 7, 5, { A_Scream }, S_HMN1_26 }, //504
+/*S_HMN1_26*/ { SPR_HMN1, 8, 3, { A_Fall }, S_HMN1_27 }, //505
+/*S_HMN1_27*/ { SPR_HMN1, 9, 4, { NULL }, S_HMN1_28 }, //506
+/*S_HMN1_28*/ { SPR_HMN1, 10, 3, { NULL }, S_HMN1_29 }, //507
+/*S_HMN1_29*/ { SPR_HMN1, 11, 3, { NULL }, S_HMN1_30 }, //508
+/*S_HMN1_30*/ { SPR_HMN1, 12, 3, { NULL }, S_HMN1_31 }, //509
+/*S_HMN1_31*/ { SPR_HMN1, 13, -1, { NULL }, S_NULL }, //510
+/*S_RGIB_08*/ { SPR_RGIB, 0, 4, { A_BodyParts }, S_RGIB_09 }, //511
+/*S_RGIB_09*/ { SPR_RGIB, 1, 4, { A_XScream }, S_RGIB_10 }, //512
+/*S_RGIB_10*/ { SPR_RGIB, 2, 3, { A_Fall }, S_RGIB_11 }, //513
+/*S_RGIB_11*/ { SPR_RGIB, 3, 3, { A_BodyParts }, S_RGIB_12 }, //514
+/*S_RGIB_12*/ { SPR_RGIB, 4, 3, { A_BodyParts }, S_RGIB_13 }, //515
+/*S_RGIB_13*/ { SPR_RGIB, 5, 3, { A_BodyParts }, S_RGIB_14 }, //516
+/*S_RGIB_14*/ { SPR_RGIB, 6, 3, { NULL }, S_RGIB_15 }, //517
+/*S_RGIB_15*/ { SPR_RGIB, 7, 1400, { NULL }, S_NULL }, //518
+/*S_LEDR_00*/ { SPR_LEDR, 2, 5, { A_FriendLook }, S_LEDR_00 }, //519
+/*S_LEDR_01*/ { SPR_LEDR, 0, 8, { NULL }, S_LEDR_00 }, //520
+/*S_LEDR_02*/ { SPR_LEDR, 1, 8, { NULL }, S_LEDR_00 }, //521
+/*S_LEAD_00*/ { SPR_LEAD, 0, 6, { A_RandomWalk }, S_LEAD_01 }, //522
+/*S_LEAD_01*/ { SPR_LEAD, 1, 6, { A_RandomWalk }, S_LEAD_02 }, //523
+/*S_LEAD_02*/ { SPR_LEAD, 2, 6, { A_RandomWalk }, S_LEAD_03 }, //524
+/*S_LEAD_03*/ { SPR_LEAD, 3, 6, { A_RandomWalk }, S_LEDR_00 }, //525
+/*S_LEAD_04*/ { SPR_LEAD, 0, 3, { A_Chase }, S_LEAD_05 }, //526
+/*S_LEAD_05*/ { SPR_LEAD, 0, 3, { A_Chase }, S_LEAD_06 }, //527
+/*S_LEAD_06*/ { SPR_LEAD, 1, 3, { A_Chase }, S_LEAD_07 }, //528
+/*S_LEAD_07*/ { SPR_LEAD, 1, 3, { A_Chase }, S_LEAD_08 }, //529
+/*S_LEAD_08*/ { SPR_LEAD, 2, 3, { A_Chase }, S_LEAD_09 }, //530
+/*S_LEAD_09*/ { SPR_LEAD, 2, 3, { A_Chase }, S_LEAD_10 }, //531
+/*S_LEAD_10*/ { SPR_LEAD, 3, 3, { A_Chase }, S_LEAD_11 }, //532
+/*S_LEAD_11*/ { SPR_LEAD, 3, 3, { A_Chase }, S_LEAD_04 }, //533
+/*S_LEAD_12*/ { SPR_LEAD, 4, 2, { A_FaceTarget }, S_LEAD_13 }, //534
+/*S_LEAD_13*/ { SPR_LEAD, 32773, 2, { A_BulletAttack }, S_LEAD_14 }, //535
+/*S_LEAD_14*/ { SPR_LEAD, 4, 1, { A_CheckTargetVisible }, S_LEAD_12 }, //536
+/*S_LEAD_15*/ { SPR_LEAD, 24, 3, { NULL }, S_LEAD_16 }, //537
+/*S_LEAD_16*/ { SPR_LEAD, 24, 3, { A_Pain }, S_LEAD_04 }, //538
+/*S_LEAD_17*/ { SPR_LEAD, 4, 4, { A_FaceTarget }, S_LEAD_18 }, //539
+/*S_LEAD_18*/ { SPR_LEAD, 32773, 4, { A_BulletAttack }, S_LEAD_19 }, //540
+/*S_LEAD_19*/ { SPR_LEAD, 4, 2, { A_CheckTargetVisible }, S_LEAD_17 }, //541
+/*S_LEAD_20*/ { SPR_LEAD, 6, 5, { NULL }, S_LEAD_21 }, //542
+/*S_LEAD_21*/ { SPR_LEAD, 7, 5, { A_Scream }, S_LEAD_22 }, //543
+/*S_LEAD_22*/ { SPR_LEAD, 8, 4, { NULL }, S_LEAD_23 }, //544
+/*S_LEAD_23*/ { SPR_LEAD, 9, 4, { NULL }, S_LEAD_24 }, //545
+/*S_LEAD_24*/ { SPR_LEAD, 10, 3, { NULL }, S_LEAD_25 }, //546
+/*S_LEAD_25*/ { SPR_LEAD, 11, 3, { A_Fall }, S_LEAD_26 }, //547
+/*S_LEAD_26*/ { SPR_LEAD, 12, 3, { NULL }, S_LEAD_27 }, //548
+/*S_LEAD_27*/ { SPR_LEAD, 13, 3, { NULL }, S_LEAD_28 }, //549
+/*S_LEAD_28*/ { SPR_LEAD, 14, 3, { NULL }, S_LEAD_29 }, //550
+/*S_LEAD_29*/ { SPR_LEAD, 15, 3, { NULL }, S_LEAD_30 }, //551
+/*S_LEAD_30*/ { SPR_LEAD, 16, 3, { NULL }, S_LEAD_31 }, //552
+/*S_LEAD_31*/ { SPR_LEAD, 17, 3, { NULL }, S_LEAD_32 }, //553
+/*S_LEAD_32*/ { SPR_LEAD, 18, 3, { NULL }, S_LEAD_33 }, //554
+/*S_LEAD_33*/ { SPR_LEAD, 19, 3, { NULL }, S_LEAD_34 }, //555
+/*S_LEAD_34*/ { SPR_LEAD, 20, 3, { NULL }, S_LEAD_35 }, //556
+/*S_LEAD_35*/ { SPR_LEAD, 21, 3, { NULL }, S_LEAD_36 }, //557
+/*S_LEAD_36*/ { SPR_LEAD, 22, 3, { A_SpawnSpectreD }, S_LEAD_37 }, //558
+/*S_LEAD_37*/ { SPR_LEAD, 23, -1, { NULL }, S_NULL }, //559
+/*S_PUFY_04*/ { SPR_PUFY, 1, 4, { NULL }, S_PUFY_05 }, //560
+/*S_PUFY_05*/ { SPR_PUFY, 2, 4, { NULL }, S_PUFY_06 }, //561
+/*S_PUFY_06*/ { SPR_PUFY, 1, 4, { NULL }, S_PUFY_07 }, //562
+/*S_PUFY_07*/ { SPR_PUFY, 2, 4, { NULL }, S_PUFY_08 }, //563
+/*S_PUFY_08*/ { SPR_PUFY, 3, 4, { NULL }, S_NULL }, //564
+/*S_MICR_01*/ { SPR_MICR, 32768, 2, { A_Tracer }, S_MICR_02 }, //565
+/*S_MICR_02*/ { SPR_MICR, 32768, 2, { A_Tracer }, S_MICR_01 }, //566
+/*S_ROB1_00*/ { SPR_ROB1, 0, 10, { A_Look }, S_ROB1_01 }, //567
+/*S_ROB1_01*/ { SPR_ROB1, 0, 10, { A_Look }, S_ROB1_00 }, //568
+/*S_ROB1_02*/ { SPR_ROB1, 1, 3, { A_Chase }, S_ROB1_03 }, //569
+/*S_ROB1_03*/ { SPR_ROB1, 1, 3, { A_Chase }, S_ROB1_04 }, //570
+/*S_ROB1_04*/ { SPR_ROB1, 2, 3, { A_Chase }, S_ROB1_05 }, //571
+/*S_ROB1_05*/ { SPR_ROB1, 2, 3, { A_Chase }, S_ROB1_06 }, //572
+/*S_ROB1_06*/ { SPR_ROB1, 3, 3, { A_Chase }, S_ROB1_07 }, //573
+/*S_ROB1_07*/ { SPR_ROB1, 3, 3, { A_Chase }, S_ROB1_08 }, //574
+/*S_ROB1_08*/ { SPR_ROB1, 4, 3, { A_Chase }, S_ROB1_09 }, //575
+/*S_ROB1_09*/ { SPR_ROB1, 4, 3, { A_Chase }, S_ROB1_02 }, //576
+/*S_ROB1_10*/ { SPR_ROB1, 7, 6, { A_FaceTarget }, S_ROB1_11 }, //577
+/*S_ROB1_11*/ { SPR_ROB1, 8, 8, { A_RobotMelee }, S_ROB1_12 }, //578
+/*S_ROB1_12*/ { SPR_ROB1, 7, 6, { NULL }, S_ROB1_02 }, //579
+/*S_ROB1_13*/ { SPR_ROB1, 5, 8, { A_FaceTarget }, S_ROB1_14 }, //580
+/*S_ROB1_14*/ { SPR_ROB1, 32774, 11, { A_ReaverAttack }, S_ROB1_02 }, //581
+/*S_ROB1_15*/ { SPR_ROB1, 0, 2, { NULL }, S_ROB1_16 }, //582
+/*S_ROB1_16*/ { SPR_ROB1, 0, 2, { A_Pain }, S_ROB1_02 }, //583
+/*S_ROB1_17*/ { SPR_ROB1, 32777, 6, { NULL }, S_ROB1_18 }, //584
+/*S_ROB1_18*/ { SPR_ROB1, 32778, 6, { A_Scream }, S_ROB1_19 }, //585
+/*S_ROB1_19*/ { SPR_ROB1, 32779, 5, { NULL }, S_ROB1_20 }, //586
+/*S_ROB1_20*/ { SPR_ROB1, 32780, 5, { A_Fall }, S_ROB1_21 }, //587
+/*S_ROB1_21*/ { SPR_ROB1, 32781, 5, { NULL }, S_ROB1_22 }, //588
+/*S_ROB1_22*/ { SPR_ROB1, 32782, 5, { NULL }, S_ROB1_23 }, //589
+/*S_ROB1_23*/ { SPR_ROB1, 32783, 5, { NULL }, S_ROB1_24 }, //590
+/*S_ROB1_24*/ { SPR_ROB1, 32784, 6, { A_DeathExplode3 }, S_ROB1_25 }, //591
+/*S_ROB1_25*/ { SPR_ROB1, 17, -1, { NULL }, S_NULL }, //592
+/*S_ROB1_26*/ { SPR_ROB1, 32779, 5, { A_BodyParts }, S_ROB1_27 }, //593
+/*S_ROB1_27*/ { SPR_ROB1, 32780, 5, { A_XScream }, S_ROB1_28 }, //594
+/*S_ROB1_28*/ { SPR_ROB1, 32781, 5, { A_BodyParts }, S_ROB1_29 }, //595
+/*S_ROB1_29*/ { SPR_ROB1, 32782, 5, { A_Fall }, S_ROB1_30 }, //596
+/*S_ROB1_30*/ { SPR_ROB1, 32783, 5, { A_BodyParts }, S_ROB1_31 }, //597
+/*S_ROB1_31*/ { SPR_ROB1, 32784, 5, { A_DeathExplode3 }, S_ROB1_32 }, //598
+/*S_ROB1_32*/ { SPR_ROB1, 17, -1, { NULL }, S_NULL }, //599
+/*S_AGRD_01*/ { SPR_AGRD, 0, 5, { A_FriendLook }, S_AGRD_01 }, //600
+/*S_AGRD_02*/ { SPR_AGRD, 1, 8, { A_ShadowOff }, S_AGRD_01 }, //601
+/*S_AGRD_03*/ { SPR_AGRD, 3, 8, { NULL }, S_AGRD_01 }, //602
+/*S_AGRD_04*/ { SPR_AGRD, 0, 5, { A_RandomWalk }, S_AGRD_05 }, //603
+/*S_AGRD_05*/ { SPR_AGRD, 1, 5, { A_RandomWalk }, S_AGRD_06 }, //604
+/*S_AGRD_06*/ { SPR_AGRD, 2, 5, { A_RandomWalk }, S_AGRD_07 }, //605
+/*S_AGRD_07*/ { SPR_AGRD, 3, 5, { A_RandomWalk }, S_AGRD_08 }, //606
+/*S_AGRD_08*/ { SPR_AGRD, 0, 5, { A_RandomWalk }, S_AGRD_09 }, //607
+/*S_AGRD_09*/ { SPR_AGRD, 1, 5, { A_RandomWalk }, S_AGRD_10 }, //608
+/*S_AGRD_10*/ { SPR_AGRD, 2, 5, { A_RandomWalk }, S_AGRD_11 }, //609
+/*S_AGRD_11*/ { SPR_AGRD, 3, 5, { A_RandomWalk }, S_AGRD_01 }, //610
+/*S_AGRD_12*/ { SPR_AGRD, 0, 6, { A_ModifyVisibility }, S_AGRD_14 }, //611
+/*S_AGRD_13*/ { SPR_AGRD, 0, 6, { A_SetTLOptions }, S_AGRD_14 }, //612
+/*S_AGRD_14*/ { SPR_AGRD, 1, 6, { A_Chase }, S_AGRD_15 }, //613
+/*S_AGRD_15*/ { SPR_AGRD, 2, 6, { A_Chase }, S_AGRD_16 }, //614
+/*S_AGRD_16*/ { SPR_AGRD, 3, 6, { A_Chase }, S_AGRD_13 }, //615
+/*S_AGRD_17*/ { SPR_AGRD, 4, 8, { A_FaceTarget }, S_AGRD_18 }, //616
+/*S_AGRD_18*/ { SPR_AGRD, 5, 4, { A_BulletAttack }, S_AGRD_19 }, //617
+/*S_AGRD_19*/ { SPR_AGRD, 4, 4, { A_BulletAttack }, S_AGRD_20 }, //618
+/*S_AGRD_20*/ { SPR_AGRD, 5, 6, { A_BulletAttack }, S_AGRD_13 }, //619
+/*S_AGRD_21*/ { SPR_AGRD, 14, 0, { A_ShadowOn }, S_AGRD_22 }, //620
+/*S_AGRD_22*/ { SPR_AGRD, 14, 8, { A_Pain }, S_AGRD_12 }, //621
+/*S_AGRD_23*/ { SPR_AGRD, 14, 8, { A_Pain }, S_AGRD_13 }, //622
+/*S_AGRD_24*/ { SPR_AGRD, 6, 4, { NULL }, S_AGRD_25 }, //623
+/*S_AGRD_25*/ { SPR_AGRD, 7, 4, { A_Scream }, S_AGRD_26 }, //624
+/*S_AGRD_26*/ { SPR_AGRD, 8, 4, { NULL }, S_AGRD_27 }, //625
+/*S_AGRD_27*/ { SPR_AGRD, 9, 3, { NULL }, S_AGRD_28 }, //626
+/*S_AGRD_28*/ { SPR_AGRD, 10, 3, { A_Fall }, S_AGRD_29 }, //627
+/*S_AGRD_29*/ { SPR_AGRD, 11, 3, { NULL }, S_AGRD_30 }, //628
+/*S_AGRD_30*/ { SPR_AGRD, 12, 3, { A_AcolyteSpecial }, S_AGRD_31 }, //629
+/*S_AGRD_31*/ { SPR_AGRD, 13, 1400, { NULL }, S_GIBS_20 }, //630
+/*S_GIBS_10*/ { SPR_GIBS, 0, 5, { A_Fall }, S_GIBS_11 }, //631
+/*S_GIBS_11*/ { SPR_GIBS, 1, 5, { A_BodyParts }, S_GIBS_12 }, //632
+/*S_GIBS_12*/ { SPR_GIBS, 2, 5, { A_BodyParts }, S_GIBS_13 }, //633
+/*S_GIBS_13*/ { SPR_GIBS, 3, 4, { A_BodyParts }, S_GIBS_14 }, //634
+/*S_GIBS_14*/ { SPR_GIBS, 4, 4, { A_XScream }, S_GIBS_15 }, //635
+/*S_GIBS_15*/ { SPR_GIBS, 5, 4, { A_BodyParts }, S_GIBS_16 }, //636
+/*S_GIBS_16*/ { SPR_GIBS, 6, 4, { NULL }, S_GIBS_17 }, //637
+/*S_GIBS_17*/ { SPR_GIBS, 7, 4, { NULL }, S_GIBS_18 }, //638
+/*S_GIBS_18*/ { SPR_GIBS, 8, 5, { NULL }, S_GIBS_19 }, //639
+/*S_GIBS_19*/ { SPR_GIBS, 9, 5, { A_AcolyteSpecial }, S_GIBS_20 }, //640
+/*S_GIBS_20*/ { SPR_GIBS, 10, 5, { NULL }, S_GIBS_21 }, //641
+/*S_GIBS_21*/ { SPR_GIBS, 11, 1400, { NULL }, S_NULL }, //642
+/*S_PGRD_00*/ { SPR_PGRD, 0, 5, { A_FriendLook }, S_PGRD_00 }, //643
+/*S_PGRD_01*/ { SPR_PGRD, 1, 10, { NULL }, S_PGRD_00 }, //644
+/*S_PGRD_02*/ { SPR_PGRD, 2, 10, { NULL }, S_PGRD_00 }, //645
+/*S_PGRD_03*/ { SPR_PGRD, 1, 10, { A_RandomWalk }, S_PGRD_00 }, //646
+/*S_PGRD_04*/ { SPR_PGRD, 0, 3, { A_Chase }, S_PGRD_05 }, //647
+/*S_PGRD_05*/ { SPR_PGRD, 0, 3, { A_Chase }, S_PGRD_06 }, //648
+/*S_PGRD_06*/ { SPR_PGRD, 1, 3, { A_Chase }, S_PGRD_07 }, //649
+/*S_PGRD_07*/ { SPR_PGRD, 1, 3, { A_Chase }, S_PGRD_08 }, //650
+/*S_PGRD_08*/ { SPR_PGRD, 2, 3, { A_Chase }, S_PGRD_09 }, //651
+/*S_PGRD_09*/ { SPR_PGRD, 2, 3, { A_Chase }, S_PGRD_10 }, //652
+/*S_PGRD_10*/ { SPR_PGRD, 3, 3, { A_Chase }, S_PGRD_11 }, //653
+/*S_PGRD_11*/ { SPR_PGRD, 3, 3, { A_Chase }, S_PGRD_04 }, //654
+/*S_PGRD_12*/ { SPR_PGRD, 4, 8, { A_FaceTarget }, S_PGRD_13 }, //655
+/*S_PGRD_13*/ { SPR_PGRD, 5, 8, { A_RobotMelee }, S_PGRD_04 }, //656
+/*S_PGRD_14*/ { SPR_PGRD, 32774, 8, { A_FaceTarget }, S_PGRD_15 }, //657
+/*S_PGRD_15*/ { SPR_PGRD, 32775, 8, { A_TemplarMauler }, S_PGRD_04 }, //658
+/*S_PGRD_16*/ { SPR_PGRD, 0, 2, { NULL }, S_PGRD_17 }, //659
+/*S_PGRD_17*/ { SPR_PGRD, 0, 2, { A_Pain }, S_PGRD_04 }, //660
+/*S_PGRD_18*/ { SPR_PGRD, 32776, 4, { A_BodyParts }, S_PGRD_19 }, //661
+/*S_PGRD_19*/ { SPR_PGRD, 32777, 4, { A_Scream }, S_PGRD_20 }, //662
+/*S_PGRD_20*/ { SPR_PGRD, 32778, 4, { A_BodyParts }, S_PGRD_21 }, //663
+/*S_PGRD_21*/ { SPR_PGRD, 32779, 4, { A_Fall }, S_PGRD_22 }, //664
+/*S_PGRD_22*/ { SPR_PGRD, 32780, 4, { NULL }, S_PGRD_23 }, //665
+/*S_PGRD_23*/ { SPR_PGRD, 32781, 4, { NULL }, S_PGRD_24 }, //666
+/*S_PGRD_24*/ { SPR_PGRD, 14, 4, { A_BodyParts }, S_PGRD_25 }, //667
+/*S_PGRD_25*/ { SPR_PGRD, 15, 4, { NULL }, S_PGRD_26 }, //668
+/*S_PGRD_26*/ { SPR_PGRD, 16, 4, { NULL }, S_PGRD_27 }, //669
+/*S_PGRD_27*/ { SPR_PGRD, 17, 4, { NULL }, S_PGRD_28 }, //670
+/*S_PGRD_28*/ { SPR_PGRD, 18, 3, { NULL }, S_PGRD_29 }, //671
+/*S_PGRD_29*/ { SPR_PGRD, 19, 3, { NULL }, S_PGRD_30 }, //672
+/*S_PGRD_30*/ { SPR_PGRD, 20, 3, { NULL }, S_PGRD_31 }, //673
+/*S_PGRD_31*/ { SPR_PGRD, 21, 3, { NULL }, S_PGRD_32 }, //674
+/*S_PGRD_32*/ { SPR_PGRD, 22, 3, { NULL }, S_PGRD_33 }, //675
+/*S_PGRD_33*/ { SPR_PGRD, 23, 3, { NULL }, S_PGRD_34 }, //676
+/*S_PGRD_34*/ { SPR_PGRD, 24, 3, { NULL }, S_PGRD_35 }, //677
+/*S_PGRD_35*/ { SPR_PGRD, 25, 3, { NULL }, S_PGRD_36 }, //678
+/*S_PGRD_36*/ { SPR_PGRD, 26, 3, { NULL }, S_PGRD_37 }, //679
+/*S_PGRD_37*/ { SPR_PGRD, 27, -1, { NULL }, S_NULL }, //680
+/*S_ROB2_00*/ { SPR_ROB2, 16, 10, { A_Look }, S_ROB2_00 }, //681
+/*S_ROB2_01*/ { SPR_ROB2, 0, 3, { A_Chase }, S_ROB2_02 }, //682
+/*S_ROB2_02*/ { SPR_ROB2, 0, 3, { A_Chase }, S_ROB2_03 }, //683
+/*S_ROB2_03*/ { SPR_ROB2, 1, 3, { A_Chase }, S_ROB2_04 }, //684
+/*S_ROB2_04*/ { SPR_ROB2, 1, 3, { A_Chase }, S_ROB2_05 }, //685
+/*S_ROB2_05*/ { SPR_ROB2, 2, 3, { A_Chase }, S_ROB2_06 }, //686
+/*S_ROB2_06*/ { SPR_ROB2, 2, 3, { A_Chase }, S_ROB2_07 }, //687
+/*S_ROB2_07*/ { SPR_ROB2, 3, 3, { A_Chase }, S_ROB2_08 }, //688
+/*S_ROB2_08*/ { SPR_ROB2, 3, 3, { A_Chase }, S_ROB2_01 }, //689
+/*S_ROB2_09*/ { SPR_ROB2, 4, 3, { A_FaceTarget }, S_ROB2_10 }, //690
+/*S_ROB2_10*/ { SPR_ROB2, 32773, 2, { A_CrusaderAttack }, S_ROB2_11 }, //691
+/*S_ROB2_11*/ { SPR_ROB2, 32772, 2, { A_CrusaderLeft }, S_ROB2_12 }, //692
+/*S_ROB2_12*/ { SPR_ROB2, 32773, 3, { A_CrusaderLeft }, S_ROB2_13 }, //693
+/*S_ROB2_13*/ { SPR_ROB2, 32772, 2, { A_CrusaderLeft }, S_ROB2_14 }, //694
+/*S_ROB2_14*/ { SPR_ROB2, 32773, 2, { A_CrusaderLeft }, S_ROB2_15 }, //695
+/*S_ROB2_15*/ { SPR_ROB2, 32772, 2, { A_CrusaderRight }, S_ROB2_16 }, //696
+/*S_ROB2_16*/ { SPR_ROB2, 32773, 2, { A_CrusaderRight }, S_ROB2_17 }, //697
+/*S_ROB2_17*/ { SPR_ROB2, 32772, 2, { A_CrusaderRight }, S_ROB2_18 }, //698
+/*S_ROB2_18*/ { SPR_ROB2, 5, 2, { A_CheckTargetVisible2 }, S_ROB2_09 }, //699
+/*S_ROB2_19*/ { SPR_ROB2, 3, 1, { A_Pain }, S_ROB2_01 }, //700
+/*S_ROB2_20*/ { SPR_ROB2, 6, 3, { A_Scream }, S_ROB2_21 }, //701
+/*S_ROB2_21*/ { SPR_ROB2, 7, 5, { A_BodyParts }, S_ROB2_22 }, //702
+/*S_ROB2_22*/ { SPR_ROB2, 32776, 4, { A_BodyParts }, S_ROB2_23 }, //703
+/*S_ROB2_23*/ { SPR_ROB2, 32777, 4, { A_DeathExplode2 }, S_ROB2_24 }, //704
+/*S_ROB2_24*/ { SPR_ROB2, 32778, 4, { A_Fall }, S_ROB2_25 }, //705
+/*S_ROB2_25*/ { SPR_ROB2, 11, 4, { A_DeathExplode2 }, S_ROB2_26 }, //706
+/*S_ROB2_26*/ { SPR_ROB2, 12, 4, { A_BodyParts }, S_ROB2_27 }, //707
+/*S_ROB2_27*/ { SPR_ROB2, 13, 4, { A_BodyParts }, S_ROB2_28 }, //708
+/*S_ROB2_28*/ { SPR_ROB2, 14, 4, { A_DeathExplode2 }, S_ROB2_29 }, //709
+/*S_ROB2_29*/ { SPR_ROB2, 15, -1, { A_BossDeath }, S_NULL }, //710
+/*S_MLDR_00*/ { SPR_MLDR, 0, 10, { A_Look }, S_MLDR_00 }, //711
+/*S_MLDR_01*/ { SPR_MLDR, 0, 3, { A_Chase }, S_MLDR_02 }, //712
+/*S_MLDR_02*/ { SPR_MLDR, 0, 3, { A_Chase }, S_MLDR_03 }, //713
+/*S_MLDR_03*/ { SPR_MLDR, 1, 3, { A_Chase }, S_MLDR_04 }, //714
+/*S_MLDR_04*/ { SPR_MLDR, 1, 3, { A_Chase }, S_MLDR_05 }, //715
+/*S_MLDR_05*/ { SPR_MLDR, 2, 3, { A_Chase }, S_MLDR_06 }, //716
+/*S_MLDR_06*/ { SPR_MLDR, 2, 3, { A_Chase }, S_MLDR_07 }, //717
+/*S_MLDR_07*/ { SPR_MLDR, 3, 3, { A_Chase }, S_MLDR_08 }, //718
+/*S_MLDR_08*/ { SPR_MLDR, 3, 3, { A_Chase }, S_MLDR_01 }, //719
+/*S_MLDR_09*/ { SPR_MLDR, 4, 3, { A_FaceTarget }, S_MLDR_10 }, //720
+/*S_MLDR_10*/ { SPR_MLDR, 32773, 2, { A_BishopAttack }, S_MLDR_01 }, //721
+/*S_MLDR_11*/ { SPR_MLDR, 3, 1, { A_Pain }, S_MLDR_01 }, //722
+/*S_MLDR_12*/ { SPR_MLDR, 32774, 3, { NULL }, S_MLDR_13 }, //723
+/*S_MLDR_13*/ { SPR_MLDR, 32775, 5, { A_Scream }, S_MLDR_14 }, //724
+/*S_MLDR_14*/ { SPR_MLDR, 32776, 4, { A_BodyParts }, S_MLDR_15 }, //725
+/*S_MLDR_15*/ { SPR_MLDR, 32777, 4, { A_DeathExplode2 }, S_MLDR_16 }, //726
+/*S_MLDR_16*/ { SPR_MLDR, 32778, 4, { NULL }, S_MLDR_17 }, //727
+/*S_MLDR_17*/ { SPR_MLDR, 32779, 4, { NULL }, S_MLDR_18 }, //728
+/*S_MLDR_18*/ { SPR_MLDR, 32780, 4, { A_Fall }, S_MLDR_19 }, //729
+/*S_MLDR_19*/ { SPR_MLDR, 32781, 4, { NULL }, S_MLDR_20 }, //730
+/*S_MLDR_20*/ { SPR_MLDR, 32782, 4, { A_BodyParts }, S_MLDR_21 }, //731
+/*S_MLDR_21*/ { SPR_MLDR, 32783, 4, { NULL }, S_MLDR_22 }, //732
+/*S_MLDR_22*/ { SPR_MLDR, 32784, 4, { A_BodyParts }, S_MLDR_23 }, //733
+/*S_MLDR_23*/ { SPR_MLDR, 32785, 4, { NULL }, S_MLDR_24 }, //734
+/*S_MLDR_24*/ { SPR_MLDR, 32786, 4, { A_BodyParts }, S_MLDR_25 }, //735
+/*S_MLDR_25*/ { SPR_MLDR, 32787, 4, { NULL }, S_MLDR_26 }, //736
+/*S_MLDR_26*/ { SPR_MLDR, 32788, 4, { A_BodyParts }, S_MLDR_27 }, //737
+/*S_MLDR_27*/ { SPR_MLDR, 21, 4, { A_SpawnSpectreB }, S_NULL }, //738
+/*S_ORCL_00*/ { SPR_ORCL, 0, -1, { NULL }, S_NULL }, //739
+/*S_ORCL_01*/ { SPR_ORCL, 1, 5, { NULL }, S_ORCL_02 }, //740
+/*S_ORCL_02*/ { SPR_ORCL, 2, 5, { NULL }, S_ORCL_03 }, //741
+/*S_ORCL_03*/ { SPR_ORCL, 3, 5, { NULL }, S_ORCL_04 }, //742
+/*S_ORCL_04*/ { SPR_ORCL, 4, 5, { NULL }, S_ORCL_05 }, //743
+/*S_ORCL_05*/ { SPR_ORCL, 5, 5, { NULL }, S_ORCL_06 }, //744
+/*S_ORCL_06*/ { SPR_ORCL, 6, 5, { NULL }, S_ORCL_07 }, //745
+/*S_ORCL_07*/ { SPR_ORCL, 7, 5, { NULL }, S_ORCL_08 }, //746
+/*S_ORCL_08*/ { SPR_ORCL, 8, 5, { NULL }, S_ORCL_09 }, //747
+/*S_ORCL_09*/ { SPR_ORCL, 9, 5, { NULL }, S_ORCL_10 }, //748
+/*S_ORCL_10*/ { SPR_ORCL, 10, 5, { NULL }, S_ORCL_11 }, //749
+/*S_ORCL_11*/ { SPR_ORCL, 11, 5, { A_Fall }, S_ORCL_12 }, //750
+/*S_ORCL_12*/ { SPR_ORCL, 12, 5, { NULL }, S_ORCL_13 }, //751
+/*S_ORCL_13*/ { SPR_ORCL, 13, 5, { A_AlertSpectreC }, S_ORCL_14 }, //752
+/*S_ORCL_14*/ { SPR_ORCL, 14, 5, { NULL }, S_ORCL_15 }, //753
+/*S_ORCL_15*/ { SPR_ORCL, 15, 5, { NULL }, S_ORCL_16 }, //754
+/*S_ORCL_16*/ { SPR_ORCL, 16, -1, { NULL }, S_NULL }, //755
+/*S_PRST_00*/ { SPR_PRST, 0, 10, { A_Look }, S_PRST_01 }, //756
+/*S_PRST_01*/ { SPR_PRST, 1, 10, { A_FloatWeave }, S_PRST_00 }, //757
+/*S_PRST_02*/ { SPR_PRST, 0, 4, { A_Chase }, S_PRST_03 }, //758
+/*S_PRST_03*/ { SPR_PRST, 0, 4, { A_FloatWeave }, S_PRST_04 }, //759
+/*S_PRST_04*/ { SPR_PRST, 1, 4, { A_Chase }, S_PRST_05 }, //760
+/*S_PRST_05*/ { SPR_PRST, 1, 4, { A_FloatWeave }, S_PRST_06 }, //761
+/*S_PRST_06*/ { SPR_PRST, 2, 4, { A_Chase }, S_PRST_07 }, //762
+/*S_PRST_07*/ { SPR_PRST, 2, 4, { A_FloatWeave }, S_PRST_08 }, //763
+/*S_PRST_08*/ { SPR_PRST, 3, 4, { A_Chase }, S_PRST_09 }, //764
+/*S_PRST_09*/ { SPR_PRST, 3, 4, { A_FloatWeave }, S_PRST_02 }, //765
+/*S_PRST_10*/ { SPR_PRST, 4, 4, { A_FaceTarget }, S_PRST_11 }, //766
+/*S_PRST_11*/ { SPR_PRST, 5, 4, { A_BossMeleeAtk }, S_PRST_12 }, //767
+/*S_PRST_12*/ { SPR_PRST, 4, 4, { A_FloatWeave }, S_PRST_02 }, //768
+/*S_PRST_13*/ { SPR_PRST, 4, 4, { A_FaceTarget }, S_PRST_14 }, //769
+/*S_PRST_14*/ { SPR_PRST, 5, 4, { A_FireHookShot }, S_PRST_15 }, //770
+/*S_PRST_15*/ { SPR_PRST, 4, 4, { A_FloatWeave }, S_PRST_02 }, //771
+/*S_PDED_00*/ { SPR_PDED, 0, 6, { NULL }, S_PDED_01 }, //772
+/*S_PDED_01*/ { SPR_PDED, 1, 6, { A_Scream }, S_PDED_02 }, //773
+/*S_PDED_02*/ { SPR_PDED, 2, 6, { NULL }, S_PDED_03 }, //774
+/*S_PDED_03*/ { SPR_PDED, 3, 6, { A_Fall }, S_PDED_04 }, //775
+/*S_PDED_04*/ { SPR_PDED, 4, 6, { NULL }, S_PDED_05 }, //776
+/*S_PDED_05*/ { SPR_PDED, 5, 5, { NULL }, S_PDED_06 }, //777
+/*S_PDED_06*/ { SPR_PDED, 6, 5, { NULL }, S_PDED_07 }, //778
+/*S_PDED_07*/ { SPR_PDED, 7, 5, { NULL }, S_PDED_08 }, //779
+/*S_PDED_08*/ { SPR_PDED, 8, 5, { NULL }, S_PDED_09 }, //780
+/*S_PDED_09*/ { SPR_PDED, 9, 5, { NULL }, S_PDED_10 }, //781
+/*S_PDED_10*/ { SPR_PDED, 8, 5, { NULL }, S_PDED_11 }, //782
+/*S_PDED_11*/ { SPR_PDED, 9, 5, { NULL }, S_PDED_12 }, //783
+/*S_PDED_12*/ { SPR_PDED, 8, 5, { NULL }, S_PDED_14 }, //784
+/*S_PDED_13*/ { SPR_PDED, 9, 5, { NULL }, S_PDED_14 }, //785
+/*S_PDED_14*/ { SPR_PDED, 10, 5, { NULL }, S_PDED_15 }, //786
+/*S_PDED_15*/ { SPR_PDED, 11, 5, { NULL }, S_PDED_16 }, //787
+/*S_PDED_16*/ { SPR_PDED, 12, 4, { NULL }, S_PDED_17 }, //788
+/*S_PDED_17*/ { SPR_PDED, 13, 4, { NULL }, S_PDED_18 }, //789
+/*S_PDED_18*/ { SPR_PDED, 14, 4, { NULL }, S_PDED_19 }, //790
+/*S_PDED_19*/ { SPR_PDED, 15, 4, { NULL }, S_PDED_20 }, //791
+/*S_PDED_20*/ { SPR_PDED, 16, 4, { A_SpawnSpectreE }, S_PDED_21 }, //792
+/*S_PDED_21*/ { SPR_PDED, 17, 4, { NULL }, S_PDED_22 }, //793
+/*S_PDED_22*/ { SPR_PDED, 18, 4, { NULL }, S_PDED_23 }, //794
+/*S_PDED_23*/ { SPR_PDED, 19, -1, { NULL }, S_NULL }, //795
+/*S_ALN1_00*/ { SPR_ALN1, 0, 10, { A_Look }, S_ALN1_01 }, //796
+/*S_ALN1_01*/ { SPR_ALN1, 1, 10, { A_FloatWeave }, S_ALN1_00 }, //797
+/*S_ALN1_02*/ { SPR_ALN1, 32768, 4, { A_Chase }, S_ALN1_03 }, //798
+/*S_ALN1_03*/ { SPR_ALN1, 32769, 4, { A_Chase }, S_ALN1_04 }, //799
+/*S_ALN1_04*/ { SPR_ALN1, 32770, 4, { A_FloatWeave }, S_ALN1_05 }, //800
+/*S_ALN1_05*/ { SPR_ALN1, 32771, 4, { A_Chase }, S_ALN1_06 }, //801
+/*S_ALN1_06*/ { SPR_ALN1, 32772, 4, { A_Chase }, S_ALN1_07 }, //802
+/*S_ALN1_07*/ { SPR_ALN1, 32773, 4, { A_Chase }, S_ALN1_08 }, //803
+/*S_ALN1_08*/ { SPR_ALN1, 32774, 4, { A_FloatWeave }, S_ALN1_09 }, //804
+/*S_ALN1_09*/ { SPR_ALN1, 32775, 4, { A_Chase }, S_ALN1_10 }, //805
+/*S_ALN1_10*/ { SPR_ALN1, 32776, 4, { A_Chase }, S_ALN1_11 }, //806
+/*S_ALN1_11*/ { SPR_ALN1, 32777, 4, { A_Chase }, S_ALN1_12 }, //807
+/*S_ALN1_12*/ { SPR_ALN1, 32778, 4, { A_FloatWeave }, S_ALN1_02 }, //808
+/*S_ALN1_13*/ { SPR_ALN1, 32777, 4, { A_FaceTarget }, S_ALN1_14 }, //809
+/*S_ALN1_14*/ { SPR_ALN1, 32776, 4, { A_BossMeleeAtk }, S_ALN1_15 }, //810
+/*S_ALN1_15*/ { SPR_ALN1, 32775, 4, { NULL }, S_ALN1_04 }, //811
+/*S_ALN1_16*/ { SPR_ALN1, 32777, 4, { A_FaceTarget }, S_ALN1_17 }, //812
+/*S_ALN1_17*/ { SPR_ALN1, 32776, 4, { A_ProgrammerAttack }, S_ALN1_18 }, //813
+/*S_ALN1_18*/ { SPR_ALN1, 32775, 4, { NULL }, S_ALN1_12 }, //814
+/*S_ALN1_19*/ { SPR_ALN1, 9, 2, { A_Pain }, S_ALN1_08 }, //815
+/*S_AL1P_00*/ { SPR_AL1P, 32768, 6, { A_NodeChunk }, S_AL1P_01 }, //816
+/*S_AL1P_01*/ { SPR_AL1P, 32769, 6, { A_Scream }, S_AL1P_02 }, //817
+/*S_AL1P_02*/ { SPR_AL1P, 32770, 6, { A_NodeChunk }, S_AL1P_03 }, //818
+/*S_AL1P_03*/ { SPR_AL1P, 32771, 6, { NULL }, S_AL1P_04 }, //819
+/*S_AL1P_04*/ { SPR_AL1P, 32772, 6, { NULL }, S_AL1P_05 }, //820
+/*S_AL1P_05*/ { SPR_AL1P, 32773, 6, { A_NodeChunk }, S_AL1P_06 }, //821
+/*S_AL1P_06*/ { SPR_AL1P, 32774, 6, { NULL }, S_AL1P_07 }, //822
+/*S_AL1P_07*/ { SPR_AL1P, 32775, 6, { A_NodeChunk }, S_AL1P_08 }, //823
+/*S_AL1P_08*/ { SPR_AL1P, 32776, 6, { NULL }, S_AL1P_09 }, //824
+/*S_AL1P_09*/ { SPR_AL1P, 32777, 6, { NULL }, S_AL1P_10 }, //825
+/*S_AL1P_10*/ { SPR_AL1P, 32778, 6, { NULL }, S_AL1P_11 }, //826
+/*S_AL1P_11*/ { SPR_AL1P, 32779, 5, { NULL }, S_AL1P_12 }, //827
+/*S_AL1P_12*/ { SPR_AL1P, 32780, 5, { NULL }, S_AL1P_13 }, //828
+/*S_AL1P_13*/ { SPR_AL1P, 32781, 5, { A_HeadChunk }, S_AL1P_14 }, //829
+/*S_AL1P_14*/ { SPR_AL1P, 32782, 5, { NULL }, S_AL1P_15 }, //830
+/*S_AL1P_15*/ { SPR_AL1P, 32783, 5, { NULL }, S_AL1P_16 }, //831
+/*S_AL1P_16*/ { SPR_AL1P, 32784, 5, { NULL }, S_AL1P_17 }, //832
+/*S_AL1P_17*/ { SPR_AL1P, 32785, 5, { A_BossDeath }, S_NULL }, //833
+/*S_NODE_00*/ { SPR_NODE, 32768, 6, { NULL }, S_NODE_01 }, //834
+/*S_NODE_01*/ { SPR_NODE, 32769, 6, { NULL }, S_NODE_02 }, //835
+/*S_NODE_02*/ { SPR_NODE, 32770, 6, { NULL }, S_NODE_03 }, //836
+/*S_NODE_03*/ { SPR_NODE, 32771, 6, { NULL }, S_NODE_04 }, //837
+/*S_NODE_04*/ { SPR_NODE, 32772, 6, { NULL }, S_NODE_05 }, //838
+/*S_NODE_05*/ { SPR_NODE, 32773, 6, { NULL }, S_NODE_06 }, //839
+/*S_NODE_06*/ { SPR_NODE, 32774, 6, { NULL }, S_NULL }, //840
+/*S_MTHD_00*/ { SPR_MTHD, 32768, 5, { NULL }, S_MTHD_01 }, //841
+/*S_MTHD_01*/ { SPR_MTHD, 32769, 5, { NULL }, S_MTHD_02 }, //842
+/*S_MTHD_02*/ { SPR_MTHD, 32770, 5, { NULL }, S_MTHD_03 }, //843
+/*S_MTHD_03*/ { SPR_MTHD, 32771, 5, { NULL }, S_MTHD_04 }, //844
+/*S_MTHD_04*/ { SPR_MTHD, 32772, 5, { NULL }, S_MTHD_05 }, //845
+/*S_MTHD_05*/ { SPR_MTHD, 32773, 5, { NULL }, S_MTHD_06 }, //846
+/*S_MTHD_06*/ { SPR_MTHD, 32774, 5, { NULL }, S_MTHD_07 }, //847
+/*S_MTHD_07*/ { SPR_MTHD, 32775, 5, { NULL }, S_MTHD_08 }, //848
+/*S_MTHD_08*/ { SPR_MTHD, 32776, 5, { NULL }, S_MTHD_09 }, //849
+/*S_MTHD_09*/ { SPR_MTHD, 32777, 5, { NULL }, S_MTHD_10 }, //850
+/*S_MTHD_10*/ { SPR_MTHD, 32778, 5, { NULL }, S_NULL }, //851
+/*S_ALN1_20*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_21 }, //852
+/*S_ALN1_21*/ { SPR_ALN1, 8, 4, { A_FireSigilEOffshoot }, S_ALN1_22 }, //853
+/*S_ALN1_22*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_12 }, //854
+/*S_ALN1_23*/ { SPR_ALN1, 0, 5, { A_FloatWeave }, S_ALN1_24 }, //855
+/*S_ALN1_24*/ { SPR_ALN1, 1, 5, { A_FloatWeave }, S_ALN1_25 }, //856
+/*S_ALN1_25*/ { SPR_ALN1, 2, 5, { A_FloatWeave }, S_ALN1_26 }, //857
+/*S_ALN1_26*/ { SPR_ALN1, 3, 5, { A_FloatWeave }, S_ALN1_27 }, //858
+/*S_ALN1_27*/ { SPR_ALN1, 4, 5, { A_FloatWeave }, S_ALN1_28 }, //859
+/*S_ALN1_28*/ { SPR_ALN1, 5, 5, { A_FloatWeave }, S_ALN1_29 }, //860
+/*S_ALN1_29*/ { SPR_ALN1, 6, 5, { A_FloatWeave }, S_ALN1_30 }, //861
+/*S_ALN1_30*/ { SPR_ALN1, 7, 5, { A_FloatWeave }, S_ALN1_31 }, //862
+/*S_ALN1_31*/ { SPR_ALN1, 8, 5, { A_FloatWeave }, S_ALN1_32 }, //863
+/*S_ALN1_32*/ { SPR_ALN1, 9, 5, { A_FloatWeave }, S_ALN1_33 }, //864
+/*S_ALN1_33*/ { SPR_ALN1, 10, 5, { A_FloatWeave }, S_ALN1_23 }, //865
+/*S_ALN1_34*/ { SPR_ALN1, 0, 5, { A_Chase }, S_ALN1_35 }, //866
+/*S_ALN1_35*/ { SPR_ALN1, 1, 5, { A_Chase }, S_ALN1_36 }, //867
+/*S_ALN1_36*/ { SPR_ALN1, 2, 5, { A_FloatWeave }, S_ALN1_37 }, //868
+/*S_ALN1_37*/ { SPR_ALN1, 3, 5, { A_Chase }, S_ALN1_38 }, //869
+/*S_ALN1_38*/ { SPR_ALN1, 4, 5, { A_Chase }, S_ALN1_39 }, //870
+/*S_ALN1_39*/ { SPR_ALN1, 5, 5, { A_Chase }, S_ALN1_40 }, //871
+/*S_ALN1_40*/ { SPR_ALN1, 6, 5, { A_FloatWeave }, S_ALN1_41 }, //872
+/*S_ALN1_41*/ { SPR_ALN1, 7, 5, { A_Chase }, S_ALN1_42 }, //873
+/*S_ALN1_42*/ { SPR_ALN1, 8, 5, { A_Chase }, S_ALN1_43 }, //874
+/*S_ALN1_43*/ { SPR_ALN1, 9, 5, { A_Chase }, S_ALN1_44 }, //875
+/*S_ALN1_44*/ { SPR_ALN1, 10, 5, { A_FloatWeave }, S_ALN1_34 }, //876
+/*S_ALN1_45*/ { SPR_ALN1, 9, 4, { A_FaceTarget }, S_ALN1_46 }, //877
+/*S_ALN1_46*/ { SPR_ALN1, 8, 4, { A_BossMeleeAtk }, S_ALN1_47 }, //878
+/*S_ALN1_47*/ { SPR_ALN1, 2, 4, { NULL }, S_ALN1_36 }, //879
+/*S_ALN1_48*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_49 }, //880
+/*S_ALN1_49*/ { SPR_ALN1, 8, 4, { A_SpectreCAttack }, S_ALN1_50 }, //881
+/*S_ALN1_50*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_44 }, //882
+/*S_ALN1_51*/ { SPR_ALN1, 9, 2, { A_Pain }, S_ALN1_40 }, //883
+/*S_ALN1_52*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_53 }, //884
+/*S_ALN1_53*/ { SPR_ALN1, 8, 4, { A_SpectreDAttack }, S_ALN1_54 }, //885
+/*S_ALN1_54*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_12 }, //886
+/*S_ALN1_55*/ { SPR_ALN1, 5, 4, { A_FaceTarget }, S_ALN1_56 }, //887
+/*S_ALN1_56*/ { SPR_ALN1, 8, 4, { A_SpectreEAttack }, S_ALN1_57 }, //888
+/*S_ALN1_57*/ { SPR_ALN1, 4, 4, { NULL }, S_ALN1_12 }, //889
+/*S_MNAM_00*/ { SPR_MNAM, 0, 100, { A_FloatWeave }, S_MNAM_01 }, //890
+/*S_MNAM_01*/ { SPR_MNAM, 32769, 60, { A_FloatWeave }, S_MNAM_02 }, //891
+/*S_MNAM_02*/ { SPR_MNAM, 32770, 4, { A_FloatWeave }, S_MNAM_03 }, //892
+/*S_MNAM_03*/ { SPR_MNAM, 32771, 4, { A_FloatWeave }, S_MNAM_04 }, //893
+/*S_MNAM_04*/ { SPR_MNAM, 32772, 4, { A_FloatWeave }, S_MNAM_05 }, //894
+/*S_MNAM_05*/ { SPR_MNAM, 32773, 4, { A_FloatWeave }, S_MNAM_06 }, //895
+/*S_MNAM_06*/ { SPR_MNAM, 32774, 4, { A_FloatWeave }, S_MNAM_07 }, //896
+/*S_MNAM_07*/ { SPR_MNAM, 32775, 4, { A_FloatWeave }, S_MNAM_08 }, //897
+/*S_MNAM_08*/ { SPR_MNAM, 32776, 4, { A_FloatWeave }, S_MNAM_09 }, //898
+/*S_MNAM_09*/ { SPR_MNAM, 32777, 4, { A_FloatWeave }, S_MNAM_10 }, //899
+/*S_MNAM_10*/ { SPR_MNAM, 32778, 4, { A_FloatWeave }, S_MNAM_11 }, //900
+/*S_MNAM_11*/ { SPR_MNAM, 32779, 4, { A_FloatWeave }, S_MNAL_00 }, //901
+/*S_MNAL_00*/ { SPR_MNAL, 32768, 4, { A_Look }, S_MNAL_01 }, //902
+/*S_MNAL_01*/ { SPR_MNAL, 32769, 4, { A_FloatWeave }, S_MNAL_00 }, //903
+/*S_MNAL_02*/ { SPR_MNAL, 32768, 4, { A_Chase }, S_MNAL_03 }, //904
+/*S_MNAL_03*/ { SPR_MNAL, 32769, 4, { A_Chase }, S_MNAL_04 }, //905
+/*S_MNAL_04*/ { SPR_MNAL, 32770, 4, { A_FloatWeave }, S_MNAL_05 }, //906
+/*S_MNAL_05*/ { SPR_MNAL, 32771, 4, { A_Chase }, S_MNAL_06 }, //907
+/*S_MNAL_06*/ { SPR_MNAL, 32772, 4, { A_Chase }, S_MNAL_07 }, //908
+/*S_MNAL_07*/ { SPR_MNAL, 32773, 4, { A_Chase }, S_MNAL_08 }, //909
+/*S_MNAL_08*/ { SPR_MNAL, 32774, 4, { A_FloatWeave }, S_MNAL_09 }, //910
+/*S_MNAL_09*/ { SPR_MNAL, 32775, 4, { A_Chase }, S_MNAL_10 }, //911
+/*S_MNAL_10*/ { SPR_MNAL, 32776, 4, { A_Chase }, S_MNAL_11 }, //912
+/*S_MNAL_11*/ { SPR_MNAL, 32777, 4, { A_Chase }, S_MNAL_12 }, //913
+/*S_MNAL_12*/ { SPR_MNAL, 32778, 4, { A_FloatWeave }, S_MNAL_02 }, //914
+/*S_MNAL_13*/ { SPR_MNAL, 32777, 4, { A_FaceTarget }, S_MNAL_14 }, //915
+/*S_MNAL_14*/ { SPR_MNAL, 32776, 4, { A_BossMeleeAtk }, S_MNAL_15 }, //916
+/*S_MNAL_15*/ { SPR_MNAL, 32770, 4, { NULL }, S_MNAL_04 }, //917
+/*S_MNAL_16*/ { SPR_MNAL, 32773, 4, { A_FaceTarget }, S_MNAL_17 }, //918
+/*S_MNAL_17*/ { SPR_MNAL, 32776, 4, { A_FireSigilWeapon }, S_MNAL_18 }, //919
+/*S_MNAL_18*/ { SPR_MNAL, 32772, 4, { NULL }, S_MNAL_12 }, //920
+/*S_MNAL_19*/ { SPR_MNAL, 32777, 2, { A_Pain }, S_MNAL_08 }, //921
+/*S_MNAL_20*/ { SPR_MNAL, 32779, 7, { A_NodeChunk }, S_MNAL_21 }, //922
+/*S_MNAL_21*/ { SPR_MNAL, 32780, 7, { A_Scream }, S_MNAL_22 }, //923
+/*S_MNAL_22*/ { SPR_MNAL, 32781, 7, { A_NodeChunk }, S_MNAL_23 }, //924
+/*S_MNAL_23*/ { SPR_MNAL, 32782, 7, { A_NodeChunk }, S_MNAL_24 }, //925
+/*S_MNAL_24*/ { SPR_MNAL, 32783, 7, { A_HeadChunk }, S_MNAL_25 }, //926
+/*S_MNAL_25*/ { SPR_MNAL, 32784, 64, { A_NodeChunk }, S_MNAL_26 }, //927
+/*S_MNAL_26*/ { SPR_MNAL, 32784, 6, { A_EntityDeath }, S_NULL }, //928
+/*S_MNAL_27*/ { SPR_MNAL, 32785, 10, { A_Look }, S_MNAL_27 }, //929
+/*S_MNAL_28*/ { SPR_MNAL, 32785, 5, { A_FloatWeave }, S_MNAL_29 }, //930
+/*S_MNAL_29*/ { SPR_MNAL, 32786, 5, { A_Chase }, S_MNAL_30 }, //931
+/*S_MNAL_30*/ { SPR_MNAL, 32787, 5, { A_Chase }, S_MNAL_31 }, //932
+/*S_MNAL_31*/ { SPR_MNAL, 32788, 5, { A_FloatWeave }, S_MNAL_32 }, //933
+/*S_MNAL_32*/ { SPR_MNAL, 32789, 5, { A_Chase }, S_MNAL_33 }, //934
+/*S_MNAL_33*/ { SPR_MNAL, 32790, 5, { A_FloatWeave }, S_MNAL_28 }, //935
+/*S_MNAL_34*/ { SPR_MNAL, 32786, 4, { A_FaceTarget }, S_MNAL_35 }, //936
+/*S_MNAL_35*/ { SPR_MNAL, 32785, 4, { A_BossMeleeAtk }, S_MNAL_36 }, //937
+/*S_MNAL_36*/ { SPR_MNAL, 32787, 4, { A_FloatWeave }, S_MNAL_29 }, //938
+/*S_MNAL_37*/ { SPR_MNAL, 32790, 4, { A_FaceTarget }, S_MNAL_38 }, //939
+/*S_MNAL_38*/ { SPR_MNAL, 32788, 4, { A_FireSigilEOffshoot }, S_MNAL_39 }, //940
+/*S_MNAL_39*/ { SPR_MNAL, 32789, 4, { A_FloatWeave }, S_MNAL_32 }, //941
+/*S_MNAL_40*/ { SPR_MNAL, 32785, 2, { A_Pain }, S_MNAL_28 }, //942
+/*S_MDTH_00*/ { SPR_MDTH, 32768, 3, { A_Scream }, S_MDTH_01 }, //943
+/*S_MDTH_01*/ { SPR_MDTH, 32769, 3, { A_BodyParts }, S_MDTH_02 }, //944
+/*S_MDTH_02*/ { SPR_MDTH, 32770, 3, { A_Fall }, S_MDTH_03 }, //945
+/*S_MDTH_03*/ { SPR_MDTH, 32771, 3, { A_BodyParts }, S_MDTH_04 }, //946
+/*S_MDTH_04*/ { SPR_MDTH, 32772, 3, { A_BodyParts }, S_MDTH_05 }, //947
+/*S_MDTH_05*/ { SPR_MDTH, 32773, 3, { A_BodyParts }, S_MDTH_06 }, //948
+/*S_MDTH_06*/ { SPR_MDTH, 32774, 3, { A_BodyParts }, S_MDTH_07 }, //949
+/*S_MDTH_07*/ { SPR_MDTH, 32775, 3, { A_BodyParts }, S_MDTH_08 }, //950
+/*S_MDTH_08*/ { SPR_MDTH, 32776, 3, { A_BodyParts }, S_MDTH_09 }, //951
+/*S_MDTH_09*/ { SPR_MDTH, 32777, 3, { A_BodyParts }, S_MDTH_10 }, //952
+/*S_MDTH_10*/ { SPR_MDTH, 32778, 3, { A_BodyParts }, S_MDTH_11 }, //953
+/*S_MDTH_11*/ { SPR_MDTH, 32779, 3, { A_BodyParts }, S_MDTH_12 }, //954
+/*S_MDTH_12*/ { SPR_MDTH, 32780, 3, { A_BodyParts }, S_MDTH_13 }, //955
+/*S_MDTH_13*/ { SPR_MDTH, 32781, 3, { A_BodyParts }, S_MDTH_14 }, //956
+/*S_MDTH_14*/ { SPR_MDTH, 32782, 3, { A_BossDeath }, S_NULL }, //957
+/*S_NEST_00*/ { SPR_NEST, 0, -1, { NULL }, S_NULL }, //958
+/*S_PODD_00*/ { SPR_PODD, 0, 60, { A_Look }, S_PODD_00 }, //959
+/*S_PODD_01*/ { SPR_PODD, 0, 360, { NULL }, S_PODD_02 }, //960
+/*S_PODD_02*/ { SPR_PODD, 1, 9, { A_Fall }, S_PODD_03 }, //961
+/*S_PODD_03*/ { SPR_PODD, 2, 9, { NULL }, S_PODD_04 }, //962
+/*S_PODD_04*/ { SPR_PODD, 3, 9, { A_SpawnEntity }, S_PODD_05 }, //963
+/*S_PODD_05*/ { SPR_PODD, 4, -1, { NULL }, S_NULL }, //964
+/*S_ZAP6_00*/ { SPR_ZAP6, 32768, 4, { NULL }, S_ZAP6_01 }, //965
+/*S_ZAP6_01*/ { SPR_ZAP6, 32769, 4, { A_SigilTrail }, S_ZAP6_02 }, //966
+/*S_ZAP6_02*/ { SPR_ZAP6, 32770, 4, { A_SigilTrail }, S_ZAP6_00 }, //967
+/*S_ZOT3_00*/ { SPR_ZOT3, 32768, 4, { NULL }, S_ZOT3_01 }, //968
+/*S_ZOT3_01*/ { SPR_ZOT3, 32769, 4, { NULL }, S_ZOT3_02 }, //969
+/*S_ZOT3_02*/ { SPR_ZOT3, 32770, 4, { NULL }, S_ZOT3_03 }, //970
+/*S_ZOT3_03*/ { SPR_ZOT3, 32771, 4, { NULL }, S_ZOT3_04 }, //971
+/*S_ZOT3_04*/ { SPR_ZOT3, 32772, 4, { NULL }, S_ZOT3_00 }, //972
+/*S_ZAP6_03*/ { SPR_ZAP6, 32768, 5, { NULL }, S_ZAP6_04 }, //973
+/*S_ZAP6_04*/ { SPR_ZAP6, 32769, 5, { NULL }, S_ZAP6_05 }, //974
+/*S_ZAP6_05*/ { SPR_ZAP6, 32770, 5, { NULL }, S_NULL }, //975
+/*S_ZAP7_00*/ { SPR_ZAP7, 32768, 4, { A_Sigil_E_Action }, S_ZAP7_01 }, //976
+/*S_ZAP7_01*/ { SPR_ZAP7, 32769, 4, { A_Sigil_E_Action }, S_ZAP7_02 }, //977
+/*S_ZAP7_02*/ { SPR_ZAP7, 32770, 6, { A_Sigil_E_Action }, S_ZAP7_03 }, //978
+/*S_ZAP7_03*/ { SPR_ZAP7, 32771, 6, { A_Sigil_E_Action }, S_ZAP7_04 }, //979
+/*S_ZAP7_04*/ { SPR_ZAP7, 32772, 6, { A_Sigil_E_Action }, S_ZAP7_00 }, //980
+/*S_ZOT1_00*/ { SPR_ZOT1, 32768, 4, { NULL }, S_ZOT1_01 }, //981
+/*S_ZOT1_01*/ { SPR_ZOT1, 32769, 4, { NULL }, S_ZOT1_02 }, //982
+/*S_ZOT1_02*/ { SPR_ZOT1, 32770, 6, { NULL }, S_ZOT1_03 }, //983
+/*S_ZOT1_03*/ { SPR_ZOT1, 32771, 6, { NULL }, S_ZOT1_04 }, //984
+/*S_ZOT1_04*/ { SPR_ZOT1, 32771, 6, { NULL }, S_ZOT1_00 }, //985
+/*S_ZAP5_00*/ { SPR_ZAP5, 32768, 4, { A_MissileTick }, S_ZAP5_01 }, //986
+/*S_ZAP5_01*/ { SPR_ZAP5, 32769, 4, { A_Sigil_A_Action }, S_ZAP5_02 }, //987
+/*S_ZAP5_02*/ { SPR_ZAP5, 32770, 4, { A_MissileTick }, S_ZAP5_03 }, //988
+/*S_ZAP5_03*/ { SPR_ZAP5, 32771, 4, { A_MissileTick }, S_ZAP5_00 }, //989
+/*S_ZOT2_00*/ { SPR_ZOT2, 32768, 4, { A_Tracer }, S_ZOT2_01 }, //990
+/*S_ZOT2_01*/ { SPR_ZOT2, 32769, 4, { A_Tracer }, S_ZOT2_02 }, //991
+/*S_ZOT2_02*/ { SPR_ZOT2, 32770, 6, { A_Tracer }, S_ZOT2_03 }, //992
+/*S_ZOT2_03*/ { SPR_ZOT2, 32771, 6, { A_Tracer }, S_ZOT2_04 }, //993
+/*S_ZOT2_04*/ { SPR_ZOT2, 32772, 5, { A_Tracer }, S_ZOT2_00 }, //994
+/*S_SEWR_00*/ { SPR_SEWR, 0, 10, { A_Look }, S_SEWR_00 }, //995
+/*S_SEWR_01*/ { SPR_SEWR, 0, 6, { A_FloatWeave }, S_SEWR_02 }, //996
+/*S_SEWR_02*/ { SPR_SEWR, 0, 6, { A_Chase }, S_SEWR_01 }, //997
+/*S_SEWR_03*/ { SPR_SEWR, 1, 4, { A_FaceTarget }, S_SEWR_04 }, //998
+/*S_SEWR_04*/ { SPR_SEWR, 32770, 8, { A_SentinelAttack }, S_SEWR_05 }, //999
+/*S_SEWR_05*/ { SPR_SEWR, 32770, 4, { A_CheckTargetVisible }, S_SEWR_04 }, //1000
+/*S_SEWR_06*/ { SPR_SEWR, 3, 5, { A_Pain }, S_SEWR_05 }, //1001
+/*S_SEWR_07*/ { SPR_SEWR, 3, 7, { A_Fall }, S_SEWR_08 }, //1002
+/*S_SEWR_08*/ { SPR_SEWR, 32772, 8, { A_BodyParts }, S_SEWR_09 }, //1003
+/*S_SEWR_09*/ { SPR_SEWR, 32773, 5, { A_Scream }, S_SEWR_10 }, //1004
+/*S_SEWR_10*/ { SPR_SEWR, 32774, 4, { A_BodyParts }, S_SEWR_11 }, //1005
+/*S_SEWR_11*/ { SPR_SEWR, 32775, 4, { A_BodyParts }, S_SEWR_12 }, //1006
+/*S_SEWR_12*/ { SPR_SEWR, 8, 4, { NULL }, S_SEWR_13 }, //1007
+/*S_SEWR_13*/ { SPR_SEWR, 9, 5, { NULL }, S_NULL }, //1008
+/*S_SPID_00*/ { SPR_SPID, 0, 1, { A_StalkerSetLook }, S_SPID_00 }, //1009
+/*S_SPID_01*/ { SPR_SPID, 0, 10, { A_Look }, S_SPID_01 }, //1010
+/*S_SPID_02*/ { SPR_SPID, 9, 10, { A_Look }, S_SPID_02 }, //1011
+/*S_SPID_03*/ { SPR_SPID, 0, 1, { A_StalkerThink }, S_SPID_04 }, //1012
+/*S_SPID_04*/ { SPR_SPID, 0, 3, { A_Chase }, S_SPID_05 }, //1013
+/*S_SPID_05*/ { SPR_SPID, 1, 3, { A_Chase }, S_SPID_06 }, //1014
+/*S_SPID_06*/ { SPR_SPID, 1, 3, { A_Chase }, S_SPID_07 }, //1015
+/*S_SPID_07*/ { SPR_SPID, 2, 3, { A_StalkerChase }, S_SPID_08 }, //1016
+/*S_SPID_08*/ { SPR_SPID, 2, 3, { A_Chase }, S_SPID_03 }, //1017
+/*S_SPID_09*/ { SPR_SPID, 9, 3, { A_FaceTarget }, S_SPID_10 }, //1018
+/*S_SPID_10*/ { SPR_SPID, 10, 3, { A_StalkerScratch }, S_SPID_18 }, //1019
+/*S_SPID_11*/ { SPR_SPID, 2, 2, { A_StalkerDrop }, S_SPID_12 }, //1020
+/*S_SPID_12*/ { SPR_SPID, 8, 3, { NULL }, S_SPID_13 }, //1021
+/*S_SPID_13*/ { SPR_SPID, 7, 3, { NULL }, S_SPID_14 }, //1022
+/*S_SPID_14*/ { SPR_SPID, 6, 3, { NULL }, S_SPID_15 }, //1023
+/*S_SPID_15*/ { SPR_SPID, 5, 3, { NULL }, S_SPID_16 }, //1024
+/*S_SPID_16*/ { SPR_SPID, 4, 3, { NULL }, S_SPID_17 }, //1025
+/*S_SPID_17*/ { SPR_SPID, 3, 3, { NULL }, S_SPID_09 }, //1026
+/*S_SPID_18*/ { SPR_SPID, 9, 3, { A_StalkerChase }, S_SPID_19 }, //1027
+/*S_SPID_19*/ { SPR_SPID, 9, 3, { A_Chase }, S_SPID_20 }, //1028
+/*S_SPID_20*/ { SPR_SPID, 10, 3, { A_Chase }, S_SPID_21 }, //1029
+/*S_SPID_21*/ { SPR_SPID, 10, 3, { A_Chase }, S_SPID_22 }, //1030
+/*S_SPID_22*/ { SPR_SPID, 11, 3, { A_StalkerChase }, S_SPID_23 }, //1031
+/*S_SPID_23*/ { SPR_SPID, 11, 3, { A_Chase }, S_SPID_18 }, //1032
+/*S_SPID_24*/ { SPR_SPID, 11, 1, { A_Pain }, S_SPID_03 }, //1033
+/*S_SPID_25*/ { SPR_SPID, 14, 4, { NULL }, S_SPID_26 }, //1034
+/*S_SPID_26*/ { SPR_SPID, 15, 4, { A_Scream }, S_SPID_27 }, //1035
+/*S_SPID_27*/ { SPR_SPID, 16, 4, { NULL }, S_SPID_28 }, //1036
+/*S_SPID_28*/ { SPR_SPID, 17, 4, { NULL }, S_SPID_29 }, //1037
+/*S_SPID_29*/ { SPR_SPID, 18, 4, { NULL }, S_SPID_30 }, //1038
+/*S_SPID_30*/ { SPR_SPID, 19, 4, { NULL }, S_SPID_31 }, //1039
+/*S_SPID_31*/ { SPR_SPID, 20, 4, { A_Fall }, S_SPID_32 }, //1040
+/*S_SPID_32*/ { SPR_SPID, 21, 4, { NULL }, S_SPID_33 }, //1041
+/*S_SPID_33*/ { SPR_SPID, 22, 4, { NULL }, S_SPID_34 }, //1042
+/*S_SPID_34*/ { SPR_SPID, 32791, 4, { NULL }, S_SPID_35 }, //1043
+/*S_SPID_35*/ { SPR_SPID, 32792, 4, { NULL }, S_SPID_36 }, //1044
+/*S_SPID_36*/ { SPR_SPID, 32793, 4, { NULL }, S_SPID_37 }, //1045
+/*S_SPID_37*/ { SPR_SPID, 32794, 4, { NULL }, S_NULL }, //1046
+/*S_ROB3_00*/ { SPR_ROB3, 0, 10, { A_Look }, S_ROB3_01 }, //1047
+/*S_ROB3_01*/ { SPR_ROB3, 1, 10, { A_Look }, S_ROB3_00 }, //1048
+/*S_ROB3_02*/ { SPR_ROB3, 1, 3, { A_InqChase }, S_ROB3_03 }, //1049
+/*S_ROB3_03*/ { SPR_ROB3, 1, 3, { A_Chase }, S_ROB3_04 }, //1050
+/*S_ROB3_04*/ { SPR_ROB3, 2, 4, { A_Chase }, S_ROB3_05 }, //1051
+/*S_ROB3_05*/ { SPR_ROB3, 2, 4, { A_Chase }, S_ROB3_06 }, //1052
+/*S_ROB3_06*/ { SPR_ROB3, 3, 4, { A_Chase }, S_ROB3_07 }, //1053
+/*S_ROB3_07*/ { SPR_ROB3, 3, 4, { A_Chase }, S_ROB3_08 }, //1054
+/*S_ROB3_08*/ { SPR_ROB3, 4, 3, { A_InqChase }, S_ROB3_09 }, //1055
+/*S_ROB3_09*/ { SPR_ROB3, 4, 3, { A_InqFlyCheck }, S_ROB3_02 }, //1056
+/*S_ROB3_10*/ { SPR_ROB3, 0, 2, { A_InqFlyCheck }, S_ROB3_11 }, //1057
+/*S_ROB3_11*/ { SPR_ROB3, 5, 6, { A_FaceTarget }, S_ROB3_12 }, //1058
+/*S_ROB3_12*/ { SPR_ROB3, 32774, 8, { A_ReaverAttack }, S_ROB3_13 }, //1059
+/*S_ROB3_13*/ { SPR_ROB3, 6, 8, { A_ReaverAttack }, S_ROB3_02 }, //1060
+/*S_ROB3_14*/ { SPR_ROB3, 10, 12, { A_FaceTarget }, S_ROB3_15 }, //1061
+/*S_ROB3_15*/ { SPR_ROB3, 32777, 6, { A_InqGrenade }, S_ROB3_16 }, //1062
+/*S_ROB3_16*/ { SPR_ROB3, 10, 12, { NULL }, S_ROB3_02 }, //1063
+/*S_ROB3_17*/ { SPR_ROB3, 32775, 8, { A_InqTakeOff }, S_ROB3_18 }, //1064
+/*S_ROB3_18*/ { SPR_ROB3, 32776, 4, { A_InqFly }, S_ROB3_19 }, //1065
+/*S_ROB3_19*/ { SPR_ROB3, 32775, 4, { A_InqFly }, S_ROB3_18 }, //1066
+/*S_ROB3_20*/ { SPR_ROB3, 11, 4, { A_BodyParts }, S_ROB3_21 }, //1067
+/*S_ROB3_21*/ { SPR_ROB3, 12, 4, { A_Scream }, S_ROB3_22 }, //1068
+/*S_ROB3_22*/ { SPR_ROB3, 13, 4, { A_BodyParts }, S_ROB3_23 }, //1069
+/*S_ROB3_23*/ { SPR_ROB3, 32782, 4, { A_DeathExplode1 }, S_ROB3_24 }, //1070
+/*S_ROB3_24*/ { SPR_ROB3, 32783, 4, { A_BodyParts }, S_ROB3_25 }, //1071
+/*S_ROB3_25*/ { SPR_ROB3, 32784, 4, { A_Fall }, S_ROB3_26 }, //1072
+/*S_ROB3_26*/ { SPR_ROB3, 17, 4, { A_BodyParts }, S_ROB3_27 }, //1073
+/*S_ROB3_27*/ { SPR_ROB3, 18, 4, { A_BodyParts }, S_ROB3_28 }, //1074
+/*S_ROB3_28*/ { SPR_ROB3, 19, 4, { A_BodyParts }, S_ROB3_29 }, //1075
+/*S_ROB3_29*/ { SPR_ROB3, 20, 4, { A_BodyParts }, S_ROB3_30 }, //1076
+/*S_ROB3_30*/ { SPR_ROB3, 21, 4, { A_BodyParts }, S_ROB3_31 }, //1077
+/*S_ROB3_31*/ { SPR_ROB3, 32790, 4, { A_DeathExplode1 }, S_ROB3_32 }, //1078
+/*S_ROB3_32*/ { SPR_ROB3, 32791, 4, { A_BodyParts }, S_ROB3_33 }, //1079
+/*S_ROB3_33*/ { SPR_ROB3, 32792, 4, { A_BodyParts }, S_ROB3_34 }, //1080
+/*S_ROB3_34*/ { SPR_ROB3, 25, 4, { A_BodyParts }, S_ROB3_35 }, //1081
+/*S_ROB3_35*/ { SPR_ROB3, 26, 4, { A_BodyParts }, S_ROB3_36 }, //1082
+/*S_ROB3_36*/ { SPR_ROB3, 27, 3, { A_BodyParts }, S_ROB3_37 }, //1083
+/*S_ROB3_37*/ { SPR_ROB3, 32796, 3, { A_DeathExplode1 }, S_RBB3_00 }, //1084
+/*S_RBB3_00*/ { SPR_RBB3, 32768, 3, { A_InqTossArm }, S_RBB3_01 }, //1085
+/*S_RBB3_01*/ { SPR_RBB3, 32769, 3, { A_BodyParts }, S_RBB3_02 }, //1086
+/*S_RBB3_02*/ { SPR_RBB3, 2, 3, { A_BodyParts }, S_RBB3_03 }, //1087
+/*S_RBB3_03*/ { SPR_RBB3, 3, 3, { A_BodyParts }, S_RBB3_04 }, //1088
+/*S_RBB3_04*/ { SPR_RBB3, 4, -1, { A_BossDeath }, S_NULL }, //1089
+/*S_RBB3_05*/ { SPR_RBB3, 32773, 5, { NULL }, S_RBB3_06 }, //1090
+/*S_RBB3_06*/ { SPR_RBB3, 32774, 5, { NULL }, S_RBB3_07 }, //1091
+/*S_RBB3_07*/ { SPR_RBB3, 7, -1, { NULL }, S_NULL }, //1092
+/*S_PRGR_00*/ { SPR_PRGR, 0, 5, { A_Look }, S_PRGR_01 }, //1093
+/*S_PRGR_01*/ { SPR_PRGR, 0, 1, { A_FloatWeave }, S_PRGR_00 }, //1094
+/*S_PRGR_02*/ { SPR_PRGR, 0, 160, { A_FloatWeave }, S_PRGR_03 }, //1095
+/*S_PRGR_03*/ { SPR_PRGR, 1, 5, { A_FloatWeave }, S_PRGR_04 }, //1096
+/*S_PRGR_04*/ { SPR_PRGR, 2, 5, { A_FloatWeave }, S_PRGR_05 }, //1097
+/*S_PRGR_05*/ { SPR_PRGR, 3, 5, { A_FloatWeave }, S_PRGR_06 }, //1098
+/*S_PRGR_06*/ { SPR_PRGR, 4, 2, { A_FloatWeave }, S_PRGR_07 }, //1099
+/*S_PRGR_07*/ { SPR_PRGR, 5, 2, { A_FloatWeave }, S_PRGR_08 }, //1100
+/*S_PRGR_08*/ { SPR_PRGR, 4, 3, { A_Chase }, S_PRGR_09 }, //1101
+/*S_PRGR_09*/ { SPR_PRGR, 5, 3, { A_Chase }, S_PRGR_06 }, //1102
+/*S_PRGR_10*/ { SPR_PRGR, 4, 2, { A_FloatWeave }, S_PRGR_11 }, //1103
+/*S_PRGR_11*/ { SPR_PRGR, 5, 3, { A_FloatWeave }, S_PRGR_12 }, //1104
+/*S_PRGR_12*/ { SPR_PRGR, 4, 3, { A_FaceTarget }, S_PRGR_13 }, //1105
+/*S_PRGR_13*/ { SPR_PRGR, 5, 4, { A_ProgrammerMelee }, S_PRGR_06 }, //1106
+/*S_PRGR_14*/ { SPR_PRGR, 6, 5, { A_FaceTarget }, S_PRGR_15 }, //1107
+/*S_PRGR_15*/ { SPR_PRGR, 7, 5, { A_FloatWeave }, S_PRGR_16 }, //1108
+/*S_PRGR_16*/ { SPR_PRGR, 32776, 5, { A_FaceTarget }, S_PRGR_17 }, //1109
+/*S_PRGR_17*/ { SPR_PRGR, 32777, 5, { A_ProgrammerAttack }, S_PRGR_06 }, //1110
+/*S_PRGR_18*/ { SPR_PRGR, 10, 5, { A_Pain }, S_PRGR_19 }, //1111
+/*S_PRGR_19*/ { SPR_PRGR, 11, 5, { A_FloatWeave }, S_PRGR_06 }, //1112
+/*S_PRGR_20*/ { SPR_PRGR, 32779, 7, { A_BodyParts }, S_PRGR_21 }, //1113
+/*S_PRGR_21*/ { SPR_PRGR, 32780, 7, { A_Scream }, S_PRGR_22 }, //1114
+/*S_PRGR_22*/ { SPR_PRGR, 32781, 7, { A_BodyParts }, S_PRGR_23 }, //1115
+/*S_PRGR_23*/ { SPR_PRGR, 32782, 7, { A_Fall }, S_PRGR_24 }, //1116
+/*S_PRGR_24*/ { SPR_PRGR, 32783, 7, { A_BodyParts }, S_PRGR_25 }, //1117
+/*S_PRGR_25*/ { SPR_PRGR, 32784, 7, { A_ProgrammerDie }, S_PRGR_26 }, //1118
+/*S_PRGR_26*/ { SPR_PRGR, 32785, 7, { NULL }, S_PRGR_27 }, //1119
+/*S_PRGR_27*/ { SPR_PRGR, 32786, 6, { NULL }, S_PRGR_28 }, //1120
+/*S_PRGR_28*/ { SPR_PRGR, 32787, 5, { NULL }, S_PRGR_29 }, //1121
+/*S_PRGR_29*/ { SPR_PRGR, 32788, 5, { NULL }, S_PRGR_30 }, //1122
+/*S_PRGR_30*/ { SPR_PRGR, 32789, 5, { NULL }, S_PRGR_31 }, //1123
+/*S_PRGR_31*/ { SPR_PRGR, 32790, 5, { NULL }, S_PRGR_32 }, //1124
+/*S_PRGR_32*/ { SPR_PRGR, 32791, 32, { NULL }, S_PRGR_33 }, //1125
+/*S_PRGR_33*/ { SPR_PRGR, 32791, -1, { A_BossDeath }, S_NULL }, //1126
+/*S_BASE_00*/ { SPR_BASE, 32768, 5, { A_DeathExplode3 }, S_BASE_01 }, //1127
+/*S_BASE_01*/ { SPR_BASE, 32769, 5, { NULL }, S_BASE_02 }, //1128
+/*S_BASE_02*/ { SPR_BASE, 32770, 5, { NULL }, S_BASE_03 }, //1129
+/*S_BASE_03*/ { SPR_BASE, 32771, 5, { NULL }, S_BASE_04 }, //1130
+/*S_BASE_04*/ { SPR_BASE, 4, 5, { NULL }, S_BASE_05 }, //1131
+/*S_BASE_05*/ { SPR_BASE, 5, 5, { NULL }, S_BASE_06 }, //1132
+/*S_BASE_06*/ { SPR_BASE, 6, 5, { NULL }, S_BASE_07 }, //1133
+/*S_BASE_07*/ { SPR_BASE, 7, -1, { NULL }, S_NULL }, //1134
+/*S_FRBL_00*/ { SPR_FRBL, 32768, 3, { NULL }, S_FRBL_01 }, //1135
+/*S_FRBL_01*/ { SPR_FRBL, 32769, 3, { NULL }, S_FRBL_02 }, //1136
+/*S_FRBL_02*/ { SPR_FRBL, 32770, 3, { A_MissileTick }, S_FRBL_00 }, //1137
+/*S_FRBL_03*/ { SPR_FRBL, 32771, 5, { A_FlameDeath }, S_FRBL_04 }, //1138
+/*S_FRBL_04*/ { SPR_FRBL, 32772, 5, { NULL }, S_FRBL_05 }, //1139
+/*S_FRBL_05*/ { SPR_FRBL, 32773, 5, { NULL }, S_FRBL_06 }, //1140
+/*S_FRBL_06*/ { SPR_FRBL, 32774, 5, { NULL }, S_FRBL_07 }, //1141
+/*S_FRBL_07*/ { SPR_FRBL, 32775, 5, { NULL }, S_FRBL_08 }, //1142
+/*S_FRBL_08*/ { SPR_FRBL, 32776, 5, { NULL }, S_NULL }, //1143
+/*S_KLAX_00*/ { SPR_KLAX, 0, 5, { A_Listen }, S_KLAX_00 }, //1144
+/*S_KLAX_01*/ { SPR_KLAX, 1, 6, { A_ClaxonBlare }, S_KLAX_02 }, //1145
+/*S_KLAX_02*/ { SPR_KLAX, 2, 60, { NULL }, S_KLAX_01 }, //1146
+/*S_TURT_00*/ { SPR_TURT, 0, 5, { A_Listen }, S_TURT_00 }, //1147
+/*S_TURT_01*/ { SPR_TURT, 0, 2, { A_Chase }, S_TURT_01 }, //1148
+/*S_TURT_02*/ { SPR_TURT, 1, 4, { A_BulletAttack }, S_TURT_03 }, //1149
+/*S_TURT_03*/ { SPR_TURT, 3, 3, { A_CheckTargetVisible }, S_TURT_04 }, //1150
+/*S_TURT_04*/ { SPR_TURT, 0, 4, { A_CheckTargetVisible }, S_TURT_02 }, //1151
+/*S_BALL_00*/ { SPR_BALL, 32768, 6, { NULL }, S_BALL_01 }, //1152
+/*S_BALL_01*/ { SPR_BALL, 32769, 6, { NULL }, S_BALL_02 }, //1153
+/*S_BALL_02*/ { SPR_BALL, 32770, 6, { NULL }, S_BALL_03 }, //1154
+/*S_BALL_03*/ { SPR_BALL, 32771, 6, { NULL }, S_BALL_04 }, //1155
+/*S_BALL_04*/ { SPR_BALL, 32772, 6, { NULL }, S_TURT_05 }, //1156
+/*S_TURT_05*/ { SPR_TURT, 2, -1, { NULL }, S_NULL }, //1157
+/*S_PSTN_00*/ { SPR_PSTN, 0, 8, { NULL }, S_PSTN_01 }, //1158
+/*S_PSTN_01*/ { SPR_PSTN, 1, 8, { NULL }, S_PSTN_00 }, //1159
+/*S_PSTN_02*/ { SPR_PSTN, 32768, 4, { A_Scream }, S_PSTN_03 }, //1160
+/*S_PSTN_03*/ { SPR_PSTN, 32769, 4, { A_Fall }, S_PSTN_04 }, //1161
+/*S_PSTN_04*/ { SPR_PSTN, 32770, 4, { A_QuestMsg }, S_PSTN_05 }, //1162
+/*S_PSTN_05*/ { SPR_PSTN, 32771, 4, { A_SpawnSparkPuff }, S_PSTN_06 }, //1163
+/*S_PSTN_06*/ { SPR_PSTN, 32772, 4, { A_BodyParts }, S_PSTN_07 }, //1164
+/*S_PSTN_07*/ { SPR_PSTN, 32773, 4, { NULL }, S_PSTN_08 }, //1165
+/*S_PSTN_08*/ { SPR_PSTN, 32774, 4, { A_SpawnSparkPuff }, S_PSTN_09 }, //1166
+/*S_PSTN_09*/ { SPR_PSTN, 7, 4, { NULL }, S_PSTN_10 }, //1167
+/*S_PSTN_10*/ { SPR_PSTN, 8, -1, { NULL }, S_NULL }, //1168
+/*S_SECR_00*/ { SPR_SECR, 32768, 4, { NULL }, S_SECR_01 }, //1169
+/*S_SECR_01*/ { SPR_SECR, 32769, 4, { NULL }, S_SECR_02 }, //1170
+/*S_SECR_02*/ { SPR_SECR, 32770, 4, { NULL }, S_SECR_03 }, //1171
+/*S_SECR_03*/ { SPR_SECR, 32771, 4, { NULL }, S_SECR_00 }, //1172
+/*S_SECR_04*/ { SPR_SECR, 32772, 5, { A_SpawnSparkPuff }, S_SECR_05 }, //1173
+/*S_SECR_05*/ { SPR_SECR, 32773, 5, { A_Fall }, S_SECR_06 }, //1174
+/*S_SECR_06*/ { SPR_SECR, 32774, 5, { A_QuestMsg }, S_SECR_07 }, //1175
+/*S_SECR_07*/ { SPR_SECR, 32775, 5, { A_BodyParts }, S_SECR_08 }, //1176
+/*S_SECR_08*/ { SPR_SECR, 32776, 5, { A_SpawnSparkPuff }, S_SECR_09 }, //1177
+/*S_SECR_09*/ { SPR_SECR, 9, 5, { NULL }, S_SECR_10 }, //1178
+/*S_SECR_10*/ { SPR_SECR, 10, 5, { A_SpawnSparkPuff }, S_SECR_11 }, //1179
+/*S_SECR_11*/ { SPR_SECR, 11, 5, { NULL }, S_SECR_12 }, //1180
+/*S_SECR_12*/ { SPR_SECR, 12, 5, { A_SpawnSparkPuff }, S_SECR_13 }, //1181
+/*S_SECR_13*/ { SPR_SECR, 13, 5, { NULL }, S_SECR_14 }, //1182
+/*S_SECR_14*/ { SPR_SECR, 14, 5, { A_SpawnSparkPuff }, S_SECR_15 }, //1183
+/*S_SECR_15*/ { SPR_SECR, 15, -1, { NULL }, S_NULL }, //1184
+/*S_XPRK_01*/ { SPR_XPRK, 0, -1, { NULL }, S_NULL }, //1185
+/*S_XPRK_02*/ { SPR_XPRK, 0, 1, { A_ClearForceField }, S_BNG3_00 }, //1186
+/*S_TARG_00*/ { SPR_TARG, 0, -1, { NULL }, S_NULL }, //1187
+/*S_RING_00*/ { SPR_RING, 0, -1, { NULL }, S_NULL }, //1188
+/*S_EARS_00*/ { SPR_EARS, 0, -1, { NULL }, S_NULL }, //1189
+/*S_COMM_00*/ { SPR_COMM, 0, -1, { NULL }, S_NULL }, //1190
+/*S_BOOM_00*/ { SPR_BOOM, 32768, 1, { A_CrystalRadiusAtk }, S_BOOM_01 }, //1191
+/*S_BOOM_01*/ { SPR_BOOM, 32769, 3, { A_QuestMsg }, S_BOOM_02 }, //1192
+/*S_BOOM_02*/ { SPR_BOOM, 32770, 2, { A_CrystalExplode }, S_BOOM_03 }, //1193
+/*S_BOOM_03*/ { SPR_BOOM, 32771, 3, { A_SpawnSparkPuff }, S_BOOM_04 }, //1194
+/*S_BOOM_04*/ { SPR_BOOM, 32772, 3, { NULL }, S_BOOM_05 }, //1195
+/*S_BOOM_05*/ { SPR_BOOM, 32773, 3, { NULL }, S_BOOM_06 }, //1196
+/*S_BOOM_06*/ { SPR_BOOM, 32774, 3, { A_SpawnSparkPuff }, S_BOOM_07 }, //1197
+/*S_BOOM_07*/ { SPR_BOOM, 32775, 1, { A_CrystalRadiusAtk }, S_BOOM_08 }, //1198
+/*S_BOOM_08*/ { SPR_BOOM, 32776, 3, { NULL }, S_BOOM_09 }, //1199
+/*S_BOOM_09*/ { SPR_BOOM, 32777, 3, { A_SpawnSparkPuff }, S_BOOM_10 }, //1200
+/*S_BOOM_10*/ { SPR_BOOM, 32778, 3, { A_SpawnSparkPuff }, S_BOOM_11 }, //1201
+/*S_BOOM_11*/ { SPR_BOOM, 32779, 3, { A_SpawnSparkPuff }, S_BOOM_12 }, //1202
+/*S_BOOM_12*/ { SPR_BOOM, 32780, 3, { NULL }, S_BOOM_13 }, //1203
+/*S_BOOM_13*/ { SPR_BOOM, 32781, 3, { NULL }, S_BOOM_14 }, //1204
+/*S_BOOM_14*/ { SPR_BOOM, 32782, 3, { A_SpawnSparkPuff }, S_BOOM_15 }, //1205
+/*S_BOOM_15*/ { SPR_BOOM, 32783, 3, { NULL }, S_BOOM_16 }, //1206
+/*S_BOOM_16*/ { SPR_BOOM, 32784, 3, { NULL }, S_BOOM_17 }, //1207
+/*S_BOOM_17*/ { SPR_BOOM, 32785, 3, { NULL }, S_BOOM_18 }, //1208
+/*S_BOOM_18*/ { SPR_BOOM, 32786, 3, { NULL }, S_BOOM_19 }, //1209
+/*S_BOOM_19*/ { SPR_BOOM, 32787, 3, { NULL }, S_BOOM_20 }, //1210
+/*S_BOOM_20*/ { SPR_BOOM, 32788, 3, { A_ExtraLightOff }, S_BOOM_21 }, //1211
+/*S_BOOM_21*/ { SPR_BOOM, 32789, 3, { NULL }, S_BOOM_22 }, //1212
+/*S_BOOM_22*/ { SPR_BOOM, 32790, 3, { NULL }, S_BOOM_23 }, //1213
+/*S_BOOM_23*/ { SPR_BOOM, 32791, 3, { NULL }, S_BOOM_24 }, //1214
+/*S_BOOM_24*/ { SPR_BOOM, 32792, 3, { NULL }, S_NULL }, //1215
+/*S_RATT_00*/ { SPR_RATT, 0, 10, { A_Look }, S_RATT_00 }, //1216
+/*S_RATT_01*/ { SPR_RATT, 0, 4, { A_Chase }, S_RATT_02 }, //1217
+/*S_RATT_02*/ { SPR_RATT, 0, 4, { A_Chase }, S_RATT_03 }, //1218
+/*S_RATT_03*/ { SPR_RATT, 1, 4, { A_Chase }, S_RATT_04 }, //1219
+/*S_RATT_04*/ { SPR_RATT, 1, 4, { A_Chase }, S_RATT_01 }, //1220
+/*S_RATT_05*/ { SPR_RATT, 0, 8, { A_RandomWalk }, S_RATT_06 }, //1221
+/*S_RATT_06*/ { SPR_RATT, 1, 4, { A_RandomWalk }, S_RATT_01 }, //1222
+/*S_HOGN_00*/ { SPR_HOGN, 0, 2, { A_ZombieInSpecialSector }, S_HOGN_00 }, //1223
+/*S_HOGN_01*/ { SPR_HOGN, 1, 1, { A_ZombieInSpecialSector }, S_HOGN_02 }, //1224
+/*S_HOGN_02*/ { SPR_HOGN, 2, 1, { A_Pain }, S_HOGN_00 }, //1225
+/*S_DEAD_00*/ { SPR_DEAD, 0, -1, { NULL }, S_NULL }, //1226
+/*S_SBAN_00*/ { SPR_SBAN, 0, -1, { NULL }, S_NULL }, //1227
+/*S_BOTR_00*/ { SPR_BOTR, 0, -1, { NULL }, S_NULL }, //1228
+/*S_HATR_00*/ { SPR_HATR, 0, -1, { NULL }, S_NULL }, //1229
+/*S_TOPR_00*/ { SPR_TOPR, 0, -1, { NULL }, S_NULL }, //1230
+/*S_COUP_00*/ { SPR_COUP, 0, 5, { NULL }, S_COUP_01 }, //1231
+/*S_COUP_01*/ { SPR_COUP, 1, 5, { NULL }, S_COUP_00 }, //1232
+/*S_COUP_02*/ { SPR_COUP, 2, -1, { NULL }, S_COUP_01 }, //1233
+/*S_BUBB_00*/ { SPR_BUBB, 0, 4, { A_ActiveSound }, S_BUBB_00 }, //1234
+/*S_BUBF_00*/ { SPR_BUBF, 0, 4, { A_ActiveSound }, S_BUBF_00 }, //1235
+/*S_BUBC_00*/ { SPR_BUBC, 0, 4, { A_ActiveSound }, S_BUBC_00 }, //1236
+/*S_ASPR_00*/ { SPR_ASPR, 0, 4, { A_ActiveSound }, S_ASPR_00 }, //1237
+/*S_SPDL_00*/ { SPR_SPDL, 0, 5, { A_ActiveSound }, S_SPDL_01 }, //1238
+/*S_SPDL_01*/ { SPR_SPDL, 1, 5, { A_ActiveSound }, S_SPDL_02 }, //1239
+/*S_SPDL_02*/ { SPR_SPDL, 2, 5, { A_ActiveSound }, S_SPDL_00 }, //1240
+/*S_TOKN_00*/ { SPR_TOKN, 0, -1, { NULL }, S_NULL }, //1241
+/*S_OTOK_00*/ { SPR_OTOK, 0, -1, { NULL }, S_NULL }, //1242
+/*S_HELT_00*/ { SPR_HELT, 0, -1, { NULL }, S_NULL }, //1243
+/*S_GUNT_00*/ { SPR_GUNT, 0, -1, { NULL }, S_NULL }, //1244
+/*S_FULL_00*/ { SPR_FULL, 0, 35, { NULL }, S_FULL_01 }, //1245
+/*S_FULL_01*/ { SPR_FULL, 1, 35, { NULL }, S_FULL_00 }, //1246
+/*S_MEAT_00*/ { SPR_MEAT, 0, 700, { NULL }, S_NULL }, //1247
+/*S_MEAT_01*/ { SPR_MEAT, 1, 700, { NULL }, S_NULL }, //1248
+/*S_MEAT_02*/ { SPR_MEAT, 2, 700, { NULL }, S_NULL }, //1249
+/*S_MEAT_03*/ { SPR_MEAT, 3, 700, { NULL }, S_NULL }, //1250
+/*S_MEAT_04*/ { SPR_MEAT, 4, 700, { NULL }, S_NULL }, //1251
+/*S_MEAT_05*/ { SPR_MEAT, 5, 700, { NULL }, S_NULL }, //1252
+/*S_MEAT_06*/ { SPR_MEAT, 6, 700, { NULL }, S_NULL }, //1253
+/*S_MEAT_07*/ { SPR_MEAT, 7, 700, { NULL }, S_NULL }, //1254
+/*S_MEAT_08*/ { SPR_MEAT, 8, 700, { NULL }, S_NULL }, //1255
+/*S_MEAT_09*/ { SPR_MEAT, 9, 700, { NULL }, S_NULL }, //1256
+/*S_MEAT_10*/ { SPR_MEAT, 10, 700, { NULL }, S_NULL }, //1257
+/*S_MEAT_11*/ { SPR_MEAT, 11, 700, { NULL }, S_NULL }, //1258
+/*S_MEAT_12*/ { SPR_MEAT, 12, 700, { NULL }, S_NULL }, //1259
+/*S_MEAT_13*/ { SPR_MEAT, 13, 700, { NULL }, S_NULL }, //1260
+/*S_MEAT_14*/ { SPR_MEAT, 14, 700, { NULL }, S_NULL }, //1261
+/*S_MEAT_15*/ { SPR_MEAT, 15, 700, { NULL }, S_NULL }, //1262
+/*S_MEAT_16*/ { SPR_MEAT, 16, 700, { NULL }, S_NULL }, //1263
+/*S_MEAT_17*/ { SPR_MEAT, 17, 700, { NULL }, S_NULL }, //1264
+/*S_MEAT_18*/ { SPR_MEAT, 18, 700, { NULL }, S_NULL }, //1265
+/*S_MEAT_19*/ { SPR_MEAT, 19, 700, { NULL }, S_NULL }, //1266
+/*S_JUNK_00*/ { SPR_JUNK, 0, 700, { NULL }, S_NULL }, //1267
+/*S_JUNK_01*/ { SPR_JUNK, 1, 700, { NULL }, S_NULL }, //1268
+/*S_JUNK_02*/ { SPR_JUNK, 2, 700, { NULL }, S_NULL }, //1269
+/*S_JUNK_03*/ { SPR_JUNK, 3, 700, { NULL }, S_NULL }, //1270
+/*S_JUNK_04*/ { SPR_JUNK, 4, 700, { NULL }, S_NULL }, //1271
+/*S_JUNK_05*/ { SPR_JUNK, 5, 700, { NULL }, S_NULL }, //1272
+/*S_JUNK_06*/ { SPR_JUNK, 6, 700, { NULL }, S_NULL }, //1273
+/*S_JUNK_07*/ { SPR_JUNK, 7, 700, { NULL }, S_NULL }, //1274
+/*S_JUNK_08*/ { SPR_JUNK, 8, 700, { NULL }, S_NULL }, //1275
+/*S_JUNK_09*/ { SPR_JUNK, 9, 700, { NULL }, S_NULL }, //1276
+/*S_JUNK_10*/ { SPR_JUNK, 10, 700, { NULL }, S_NULL }, //1277
+/*S_JUNK_11*/ { SPR_JUNK, 11, 700, { NULL }, S_NULL }, //1278
+/*S_JUNK_12*/ { SPR_JUNK, 12, 700, { NULL }, S_NULL }, //1279
+/*S_JUNK_13*/ { SPR_JUNK, 13, 700, { NULL }, S_NULL }, //1280
+/*S_JUNK_14*/ { SPR_JUNK, 14, 700, { NULL }, S_NULL }, //1281
+/*S_JUNK_15*/ { SPR_JUNK, 15, 700, { NULL }, S_NULL }, //1282
+/*S_JUNK_16*/ { SPR_JUNK, 16, 700, { NULL }, S_NULL }, //1283
+/*S_JUNK_17*/ { SPR_JUNK, 17, 700, { NULL }, S_NULL }, //1284
+/*S_JUNK_18*/ { SPR_JUNK, 18, 700, { NULL }, S_NULL }, //1285
+/*S_JUNK_19*/ { SPR_JUNK, 19, 700, { NULL }, S_NULL }, //1286
+/*S_FFOT_00*/ { SPR_FFOT, 0, 9, { NULL }, S_FFOT_01 }, //1287
+/*S_FFOT_01*/ { SPR_FFOT, 1, 9, { NULL }, S_FFOT_02 }, //1288
+/*S_FFOT_02*/ { SPR_FFOT, 2, 9, { NULL }, S_FFOT_03 }, //1289
+/*S_FFOT_03*/ { SPR_FFOT, 3, 9, { NULL }, S_NULL }, //1290
+/*S_DIE1_00*/ { SPR_DIE1, 0, -1, { NULL }, S_NULL }, //1291
+/*S_BEAC_00*/ { SPR_BEAC, 0, -1, { NULL }, S_NULL }, //1292
+/*S_BEAC_01*/ { SPR_BEAC, 0, 30, { NULL }, S_BEAC_02 }, //1293
+/*S_BEAC_02*/ { SPR_BEAC, 0, 160, { A_TeleportBeacon }, S_BEAC_01 }, //1294
+/*S_ARM1_00*/ { SPR_ARM1, 0, -1, { NULL }, S_NULL }, //1295
+/*S_ARM2_00*/ { SPR_ARM2, 0, -1, { NULL }, S_NULL }, //1296
+/*S_BARW_00*/ { SPR_BARW, 0, -1, { NULL }, S_NULL }, //1297
+/*S_BARW_01*/ { SPR_BARW, 1, 2, { A_Scream }, S_BARW_02 }, //1298
+/*S_BARW_02*/ { SPR_BARW, 2, 2, { NULL }, S_BARW_03 }, //1299
+/*S_BARW_03*/ { SPR_BARW, 3, 2, { A_Fall }, S_BARW_04 }, //1300
+/*S_BARW_04*/ { SPR_BARW, 4, 2, { NULL }, S_BARW_05 }, //1301
+/*S_BARW_05*/ { SPR_BARW, 5, 2, { NULL }, S_BARW_06 }, //1302
+/*S_BARW_06*/ { SPR_BARW, 6, 2, { NULL }, S_BARW_07 }, //1303
+/*S_BARW_07*/ { SPR_BARW, 7, -1, { NULL }, S_NULL }, //1304
+/*S_BART_00*/ { SPR_BART, 0, -1, { NULL }, S_NULL }, //1305
+/*S_BART_01*/ { SPR_BART, 32769, 2, { A_Scream }, S_BART_02 }, //1306
+/*S_BART_02*/ { SPR_BART, 32770, 2, { NULL }, S_BART_03 }, //1307
+/*S_BART_03*/ { SPR_BART, 32771, 2, { NULL }, S_BART_04 }, //1308
+/*S_BART_04*/ { SPR_BART, 32772, 2, { A_Fall }, S_BART_05 }, //1309
+/*S_BART_05*/ { SPR_BART, 32773, 2, { A_DeathExplode2 }, S_BART_06 }, //1310
+/*S_BART_06*/ { SPR_BART, 32774, 2, { NULL }, S_BART_07 }, //1311
+/*S_BART_07*/ { SPR_BART, 32775, 2, { NULL }, S_BART_08 }, //1312
+/*S_BART_08*/ { SPR_BART, 32776, 2, { NULL }, S_BART_09 }, //1313
+/*S_BART_09*/ { SPR_BART, 32777, 3, { NULL }, S_BART_10 }, //1314
+/*S_BART_10*/ { SPR_BART, 32778, 3, { NULL }, S_BART_11 }, //1315
+/*S_BART_11*/ { SPR_BART, 11, -1, { NULL }, S_NULL }, //1316
+/*S_LAMP_00*/ { SPR_LAMP, 0, -1, { NULL }, S_NULL }, //1317
+/*S_LANT_00*/ { SPR_LANT, 0, -1, { NULL }, S_NULL }, //1318
+/*S_BARL_00*/ { SPR_BARL, 32768, 4, { NULL }, S_BARL_01 }, //1319
+/*S_BARL_01*/ { SPR_BARL, 32769, 4, { NULL }, S_BARL_02 }, //1320
+/*S_BARL_02*/ { SPR_BARL, 32770, 4, { NULL }, S_BARL_03 }, //1321
+/*S_BARL_03*/ { SPR_BARL, 32771, 4, { NULL }, S_BARL_00 }, //1322
+/*S_BOWL_00*/ { SPR_BOWL, 32768, 4, { A_ActiveSound }, S_BOWL_01 }, //1323
+/*S_BOWL_01*/ { SPR_BOWL, 32769, 4, { NULL }, S_BOWL_02 }, //1324
+/*S_BOWL_02*/ { SPR_BOWL, 32770, 4, { NULL }, S_BOWL_03 }, //1325
+/*S_BOWL_03*/ { SPR_BOWL, 32771, 4, { NULL }, S_BOWL_00 }, //1326
+/*S_BRAZ_00*/ { SPR_BRAZ, 32768, 4, { A_ActiveSound }, S_BRAZ_01 }, //1327
+/*S_BRAZ_01*/ { SPR_BRAZ, 32769, 4, { NULL }, S_BRAZ_02 }, //1328
+/*S_BRAZ_02*/ { SPR_BRAZ, 32770, 4, { NULL }, S_BRAZ_03 }, //1329
+/*S_BRAZ_03*/ { SPR_BRAZ, 32771, 4, { NULL }, S_BRAZ_00 }, //1330
+/*S_TRCH_00*/ { SPR_TRCH, 32768, 4, { A_ActiveSound }, S_TRCH_01 }, //1331
+/*S_TRCH_01*/ { SPR_TRCH, 32769, 4, { NULL }, S_TRCH_02 }, //1332
+/*S_TRCH_02*/ { SPR_TRCH, 32770, 4, { NULL }, S_TRCH_03 }, //1333
+/*S_TRCH_03*/ { SPR_TRCH, 32771, 4, { NULL }, S_TRCH_00 }, //1334
+/*S_LTRH_00*/ { SPR_LTRH, 32768, 4, { NULL }, S_LTRH_01 }, //1335
+/*S_LTRH_01*/ { SPR_LTRH, 32769, 4, { NULL }, S_LTRH_02 }, //1336
+/*S_LTRH_02*/ { SPR_LTRH, 32770, 4, { NULL }, S_LTRH_03 }, //1337
+/*S_LTRH_03*/ { SPR_LTRH, 32771, 4, { NULL }, S_LTRH_00 }, //1338
+/*S_LMPC_00*/ { SPR_LMPC, 32768, 4, { A_ActiveSound }, S_LMPC_01 }, //1339
+/*S_LMPC_01*/ { SPR_LMPC, 32769, 4, { NULL }, S_LMPC_02 }, //1340
+/*S_LMPC_02*/ { SPR_LMPC, 32770, 4, { NULL }, S_LMPC_03 }, //1341
+/*S_LMPC_03*/ { SPR_LMPC, 32771, 4, { NULL }, S_LMPC_00 }, //1342
+/*S_LOGS_00*/ { SPR_LOGS, 32768, 4, { A_ActiveSound }, S_LOGS_01 }, //1343
+/*S_LOGS_01*/ { SPR_LOGS, 32769, 4, { NULL }, S_LOGS_02 }, //1344
+/*S_LOGS_02*/ { SPR_LOGS, 32770, 4, { NULL }, S_LOGS_03 }, //1345
+/*S_LOGS_03*/ { SPR_LOGS, 32771, 4, { NULL }, S_LOGS_00 }, //1346
+/*S_TRHO_00*/ { SPR_TRHO, 0, -1, { NULL }, S_NULL }, //1347
+/*S_WATR_00*/ { SPR_WATR, 0, -1, { NULL }, S_NULL }, //1348
+/*S_MUGG_00*/ { SPR_MUGG, 0, -1, { NULL }, S_NULL }, //1349
+/*S_FUSL_00*/ { SPR_FUSL, 0, -1, { NULL }, S_NULL }, //1350
+/*S_CRD1_00*/ { SPR_CRD1, 0, -1, { NULL }, S_NULL }, //1351
+/*S_CRD2_00*/ { SPR_CRD2, 0, -1, { NULL }, S_NULL }, //1352
+/*S_TPAS_00*/ { SPR_TPAS, 0, -1, { NULL }, S_NULL }, //1353
+/*S_KY1G_00*/ { SPR_KY1G, 0, -1, { NULL }, S_NULL }, //1354
+/*S_KY2S_00*/ { SPR_KY2S, 0, -1, { NULL }, S_NULL }, //1355
+/*S_KY3B_00*/ { SPR_KY3B, 0, -1, { NULL }, S_NULL }, //1356
+/*S_HAND_00*/ { SPR_HAND, 0, -1, { NULL }, S_NULL }, //1357
+/*S_CRYS_00*/ { SPR_CRYS, 0, 16, { A_ActiveSound }, S_CRYS_01 }, //1358
+/*S_CRYS_01*/ { SPR_CRYS, 1, 5, { A_ActiveSound }, S_CRYS_02 }, //1359
+/*S_CRYS_02*/ { SPR_CRYS, 2, 4, { A_ActiveSound }, S_CRYS_03 }, //1360
+/*S_CRYS_03*/ { SPR_CRYS, 3, 4, { A_ActiveSound }, S_CRYS_04 }, //1361
+/*S_CRYS_04*/ { SPR_CRYS, 4, 4, { A_ActiveSound }, S_CRYS_05 }, //1362
+/*S_CRYS_05*/ { SPR_CRYS, 5, 4, { A_ActiveSound }, S_CRYS_00 }, //1363
+/*S_PRIS_00*/ { SPR_PRIS, 0, -1, { NULL }, S_NULL }, //1364
+/*S_PWR1_00*/ { SPR_PWR1, 0, -1, { NULL }, S_NULL }, //1365
+/*S_PWR2_00*/ { SPR_PWR2, 0, -1, { NULL }, S_NULL }, //1366
+/*S_PWR3_00*/ { SPR_PWR3, 0, -1, { NULL }, S_NULL }, //1367
+/*S_ORAC_00*/ { SPR_ORAC, 0, -1, { NULL }, S_NULL }, //1368
+/*S_GYID_00*/ { SPR_GYID, 0, -1, { NULL }, S_NULL }, //1369
+/*S_FUBR_00*/ { SPR_FUBR, 0, -1, { NULL }, S_NULL }, //1370
+/*S_WARE_00*/ { SPR_WARE, 0, -1, { NULL }, S_NULL }, //1371
+/*S_RCRY_00*/ { SPR_RCRY, 32768, -1, { NULL }, S_NULL }, //1372
+/*S_BCRY_00*/ { SPR_BCRY, 32768, -1, { NULL }, S_NULL }, //1373
+/*S_CHAP_00*/ { SPR_CHAP, 0, -1, { NULL }, S_NULL }, //1374
+/*S_TUNL_00*/ { SPR_TUNL, 0, -1, { NULL }, S_NULL }, //1375
+/*S_BLTK_00*/ { SPR_BLTK, 0, -1, { NULL }, S_NULL }, //1376
+/*S_SECK_00*/ { SPR_SECK, 0, -1, { NULL }, S_NULL }, //1377
+/*S_MINE_00*/ { SPR_MINE, 0, -1, { NULL }, S_NULL }, //1378
+/*S_REBL_00*/ { SPR_REBL, 0, -1, { NULL }, S_NULL }, //1379
+/*S_PROC_00*/ { SPR_PROC, 0, -1, { NULL }, S_NULL }, //1380
+/*S_ANKH_00*/ { SPR_ANKH, 0, -1, { NULL }, S_NULL }, //1381
+/*S_GOID_00*/ { SPR_GOID, 0, -1, { NULL }, S_NULL }, //1382
+/*S_STMP_00*/ { SPR_STMP, 0, -1, { NULL }, S_NULL }, //1383
+/*S_MDKT_00*/ { SPR_MDKT, 0, -1, { NULL }, S_NULL }, //1384
+/*S_COIN_00*/ { SPR_COIN, 0, -1, { NULL }, S_NULL }, //1385
+/*S_CRED_00*/ { SPR_CRED, 0, -1, { NULL }, S_NULL }, //1386
+/*S_SACK_00*/ { SPR_SACK, 0, -1, { NULL }, S_NULL }, //1387
+/*S_CHST_00*/ { SPR_CHST, 0, -1, { NULL }, S_NULL }, //1388
+/*S_SHD1_00*/ { SPR_SHD1, 0, 17, { A_ShadowOff }, S_SHD1_01 }, //1389
+/*S_SHD1_01*/ { SPR_SHD1, 0, 17, { A_ModifyVisibility }, S_SHD1_02 }, //1390
+/*S_SHD1_02*/ { SPR_SHD1, 0, 17, { A_ShadowOn }, S_SHD1_03 }, //1391
+/*S_SHD1_03*/ { SPR_SHD1, 0, 17, { A_ModifyVisibility }, S_SHD1_00 }, //1392
+/*S_MASK_00*/ { SPR_MASK, 0, -1, { NULL }, S_NULL }, //1393
+/*S_UNIF_00*/ { SPR_UNIF, 0, -1, { NULL }, S_NULL }, //1394
+/*S_OFIC_00*/ { SPR_OFIC, 0, -1, { NULL }, S_NULL }, //1395
+/*S_PMAP_00*/ { SPR_PMAP, 32768, 6, { NULL }, S_PMAP_01 }, //1396
+/*S_PMAP_01*/ { SPR_PMAP, 32769, 6, { NULL }, S_PMAP_00 }, //1397
+/*S_PMUP_00*/ { SPR_PMUP, 32768, 6, { NULL }, S_PMUP_01 }, //1398
+/*S_PMUP_01*/ { SPR_PMUP, 32769, 6, { NULL }, S_PMUP_00 }, //1399
+/*S_BLIT_00*/ { SPR_BLIT, 0, -1, { NULL }, S_NULL }, //1400
+/*S_BBOX_00*/ { SPR_BBOX, 0, -1, { NULL }, S_NULL }, //1401
+/*S_MSSL_00*/ { SPR_MSSL, 0, -1, { NULL }, S_NULL }, //1402
+/*S_ROKT_00*/ { SPR_ROKT, 0, -1, { NULL }, S_NULL }, //1403
+/*S_BRY1_00*/ { SPR_BRY1, 0, 6, { NULL }, S_BRY1_01 }, //1404
+/*S_BRY1_01*/ { SPR_BRY1, 1, 6, { NULL }, S_BRY1_00 }, //1405
+/*S_CPAC_00*/ { SPR_CPAC, 0, 6, { NULL }, S_CPAC_01 }, //1406
+/*S_CPAC_01*/ { SPR_CPAC, 1, 6, { NULL }, S_CPAC_00 }, //1407
+/*S_PQRL_00*/ { SPR_PQRL, 0, -1, { NULL }, S_NULL }, //1408
+/*S_XQRL_00*/ { SPR_XQRL, 0, -1, { NULL }, S_NULL }, //1409
+/*S_GRN1_00*/ { SPR_GRN1, 0, -1, { NULL }, S_NULL }, //1410
+/*S_GRN2_00*/ { SPR_GRN2, 0, -1, { NULL }, S_NULL }, //1411
+/*S_BKPK_00*/ { SPR_BKPK, 0, -1, { NULL }, S_NULL }, //1412
+/*S_RELC_00*/ { SPR_RELC, 32768, -1, { NULL }, S_NULL }, //1413
+/*S_RIFL_00*/ { SPR_RIFL, 0, -1, { NULL }, S_NULL }, //1414
+/*S_RIFL_01*/ { SPR_RIFL, 1, -1, { NULL }, S_NULL }, //1415
+/*S_FLAM_00*/ { SPR_FLAM, 0, -1, { NULL }, S_NULL }, //1416
+/*S_BFLM_00*/ { SPR_BFLM, 0, -1, { NULL }, S_NULL }, //1417
+/*S_MMSL_00*/ { SPR_MMSL, 0, -1, { NULL }, S_NULL }, //1418
+/*S_TRPD_00*/ { SPR_TRPD, 0, -1, { NULL }, S_NULL }, //1419
+/*S_GRND_00*/ { SPR_GRND, 0, -1, { NULL }, S_NULL }, //1420
+/*S_CBOW_00*/ { SPR_CBOW, 0, -1, { NULL }, S_NULL }, //1421
+/*S_SIGL_00*/ { SPR_SIGL, 0, -1, { NULL }, S_NULL }, //1422
+/*S_SIGL_01*/ { SPR_SIGL, 1, -1, { NULL }, S_NULL }, //1423
+/*S_SIGL_02*/ { SPR_SIGL, 2, -1, { NULL }, S_NULL }, //1424
+/*S_SIGL_03*/ { SPR_SIGL, 3, -1, { NULL }, S_NULL }, //1425
+/*S_SIGL_04*/ { SPR_SIGL, 4, -1, { NULL }, S_NULL }, //1426
+/*S_LITE_00*/ { SPR_LITE, 32768, -1, { NULL }, S_NULL }, //1427
+/*S_CNDL_00*/ { SPR_CNDL, 32768, -1, { NULL }, S_NULL }, //1428
+/*S_CLBR_00*/ { SPR_CLBR, 32768, -1, { NULL }, S_NULL }, //1429
+/*S_LITS_00*/ { SPR_LITS, 32768, -1, { NULL }, S_NULL }, //1430
+/*S_LITB_00*/ { SPR_LITB, 32768, -1, { NULL }, S_NULL }, //1431
+/*S_LITG_00*/ { SPR_LITG, 32768, -1, { NULL }, S_NULL }, //1432
+/*S_ROK1_00*/ { SPR_ROK1, 0, -1, { NULL }, S_NULL }, //1433
+/*S_ROK2_00*/ { SPR_ROK2, 0, -1, { NULL }, S_NULL }, //1434
+/*S_ROK3_00*/ { SPR_ROK3, 0, -1, { NULL }, S_NULL }, //1435
+/*S_ROK4_00*/ { SPR_ROK4, 0, -1, { NULL }, S_NULL }, //1436
+/*S_LOGG_00*/ { SPR_LOGG, 0, 5, { A_ActiveSound }, S_LOGG_01 }, //1437
+/*S_LOGG_01*/ { SPR_LOGG, 1, 5, { A_ActiveSound }, S_LOGG_02 }, //1438
+/*S_LOGG_02*/ { SPR_LOGG, 2, 5, { A_ActiveSound }, S_LOGG_03 }, //1439
+/*S_LOGG_03*/ { SPR_LOGG, 3, 5, { A_ActiveSound }, S_LOGG_00 }, //1440
+/*S_RUB1_00*/ { SPR_RUB1, 0, -1, { NULL }, S_NULL }, //1441
+/*S_RUB2_00*/ { SPR_RUB2, 0, -1, { NULL }, S_NULL }, //1442
+/*S_RUB3_00*/ { SPR_RUB3, 0, -1, { NULL }, S_NULL }, //1443
+/*S_RUB4_00*/ { SPR_RUB4, 0, -1, { NULL }, S_NULL }, //1444
+/*S_RUB5_00*/ { SPR_RUB5, 0, -1, { NULL }, S_NULL }, //1445
+/*S_RUB6_00*/ { SPR_RUB6, 0, -1, { NULL }, S_NULL }, //1446
+/*S_RUB7_00*/ { SPR_RUB7, 0, -1, { NULL }, S_NULL }, //1447
+/*S_RUB8_00*/ { SPR_RUB8, 0, -1, { NULL }, S_NULL }, //1448
+/*S_CHAN_00*/ { SPR_CHAN, 0, -1, { NULL }, S_NULL }, //1449
+/*S_STAT_00*/ { SPR_STAT, 0, -1, { NULL }, S_NULL }, //1450
+/*S_DSTA_00*/ { SPR_DSTA, 0, -1, { NULL }, S_NULL }, //1451
+/*S_CRAB_00*/ { SPR_CRAB, 0, -1, { NULL }, S_NULL }, //1452
+/*S_CAGE_00*/ { SPR_CAGE, 0, -1, { NULL }, S_NULL }, //1453
+/*S_TREE_00*/ { SPR_TREE, 0, -1, { NULL }, S_NULL }, //1454
+/*S_TREE_01*/ { SPR_TREE, 1, -1, { NULL }, S_NULL }, //1455
+/*S_TREE_02*/ { SPR_TREE, 2, -1, { NULL }, S_NULL }, //1456
+/*S_TRE1_00*/ { SPR_TRE1, 0, -1, { NULL }, S_NULL }, //1457
+/*S_BUSH_00*/ { SPR_BUSH, 0, -1, { NULL }, S_NULL }, //1458
+/*S_SHRB_00*/ { SPR_SHRB, 0, -1, { NULL }, S_NULL }, //1459
+/*S_STAK_00*/ { SPR_STAK, 0, -1, { NULL }, S_NULL }, //1460
+/*S_BAR1_00*/ { SPR_BAR1, 0, -1, { NULL }, S_NULL }, //1461
+/*S_VASE_00*/ { SPR_VASE, 0, -1, { NULL }, S_NULL }, //1462
+/*S_VASE_01*/ { SPR_VASE, 1, -1, { NULL }, S_NULL }, //1463
+/*S_STOL_00*/ { SPR_STOL, 0, -1, { NULL }, S_NULL }, //1464
+/*S_POT1_00*/ { SPR_POT1, 0, -1, { NULL }, S_NULL }, //1465
+/*S_TUB1_00*/ { SPR_TUB1, 0, -1, { NULL }, S_NULL }, //1466
+/*S_ANVL_00*/ { SPR_ANVL, 0, -1, { NULL }, S_NULL }, //1467
+/*S_TLMP_00*/ { SPR_TLMP, 0, -1, { NULL }, S_NULL }, //1468
+/*S_TLMP_01*/ { SPR_TLMP, 1, -1, { NULL }, S_NULL }, //1469
+/*S_TRAY_00*/ { SPR_TRAY, 0, -1, { NULL }, S_NULL }, //1470
+/*S_APOW_00*/ { SPR_APOW, 0, 4, { A_ActiveSound }, S_APOW_00 }, //1471
+/*S_AFED_00*/ { SPR_AFED, 0, -1, { NULL }, S_NULL }, //1472
+/*S_DRIP_00*/ { SPR_DRIP, 0, 6, { A_ActiveSound }, S_DRIP_01 }, //1473
+/*S_DRIP_01*/ { SPR_DRIP, 1, 4, { NULL }, S_DRIP_02 }, //1474
+/*S_DRIP_02*/ { SPR_DRIP, 2, 4, { NULL }, S_DRIP_03 }, //1475
+/*S_DRIP_03*/ { SPR_DRIP, 3, 4, { A_ActiveSound }, S_DRIP_04 }, //1476
+/*S_DRIP_04*/ { SPR_DRIP, 4, 4, { NULL }, S_DRIP_05 }, //1477
+/*S_DRIP_05*/ { SPR_DRIP, 5, 4, { NULL }, S_DRIP_06 }, //1478
+/*S_DRIP_06*/ { SPR_DRIP, 6, 4, { A_ActiveSound }, S_DRIP_07 }, //1479
+/*S_DRIP_07*/ { SPR_DRIP, 7, 4, { NULL }, S_DRIP_00 }, //1480
+/*S_CDRP_00*/ { SPR_CDRP, 0, 10, { NULL }, S_CDRP_01 }, //1481
+/*S_CDRP_01*/ { SPR_CDRP, 1, 8, { NULL }, S_CDRP_02 }, //1482
+/*S_CDRP_02*/ { SPR_CDRP, 2, 8, { NULL }, S_CDRP_03 }, //1483
+/*S_CDRP_03*/ { SPR_CDRP, 3, 8, { NULL }, S_CDRP_00 }, //1484
+/*S_SPLH_00*/ { SPR_SPLH, 0, 4, { NULL }, S_SPLH_01 }, //1485
+/*S_SPLH_01*/ { SPR_SPLH, 1, 4, { NULL }, S_SPLH_02 }, //1486
+/*S_SPLH_02*/ { SPR_SPLH, 2, 4, { NULL }, S_SPLH_03 }, //1487
+/*S_SPLH_03*/ { SPR_SPLH, 3, 8, { NULL }, S_SPLH_04 }, //1488
+/*S_SPLH_04*/ { SPR_SPLH, 4, 4, { NULL }, S_SPLH_05 }, //1489
+/*S_SPLH_05*/ { SPR_SPLH, 5, 4, { NULL }, S_SPLH_06 }, //1490
+/*S_SPLH_06*/ { SPR_SPLH, 6, 4, { NULL }, S_SPLH_07 }, //1491
+/*S_SPLH_07*/ { SPR_SPLH, 7, 4, { A_ActiveSound }, S_SPLH_00 }, //1492
+/*S_WTFT_00*/ { SPR_WTFT, 0, 4, { NULL }, S_WTFT_01 }, //1493
+/*S_WTFT_01*/ { SPR_WTFT, 1, 4, { NULL }, S_WTFT_02 }, //1494
+/*S_WTFT_02*/ { SPR_WTFT, 2, 4, { NULL }, S_WTFT_03 }, //1495
+/*S_WTFT_03*/ { SPR_WTFT, 3, 4, { A_ActiveSound }, S_WTFT_00 }, //1496
+/*S_HERT_00*/ { SPR_HERT, 32768, 4, { NULL }, S_HERT_01 }, //1497
+/*S_HERT_01*/ { SPR_HERT, 32769, 4, { NULL }, S_HERT_02 }, //1498
+/*S_HERT_02*/ { SPR_HERT, 32770, 4, { NULL }, S_HERT_00 }, //1499
+/*S_TELP_00*/ { SPR_TELP, 32768, 3, { NULL }, S_TELP_01 }, //1500
+/*S_TELP_01*/ { SPR_TELP, 32769, 3, { NULL }, S_TELP_02 }, //1501
+/*S_TELP_02*/ { SPR_TELP, 32770, 3, { NULL }, S_TELP_03 }, //1502
+/*S_TELP_03*/ { SPR_TELP, 32771, 3, { NULL }, S_TELP_00 }, //1503
+/*S_MONI_00*/ { SPR_MONI, 0, -1, { NULL }, S_NULL }, //1504
+/*S_STEL_00*/ { SPR_STEL, 0, -1, { NULL }, S_NULL }, //1505
+/*S_STLA_00*/ { SPR_STLA, 0, -1, { NULL }, S_NULL }, //1506
+/*S_STLE_00*/ { SPR_STLE, 0, -1, { NULL }, S_NULL }, //1507
+/*S_HUGE_00*/ { SPR_HUGE, 0, 4, { NULL }, S_HUGE_01 }, //1508
+/*S_HUGE_01*/ { SPR_HUGE, 1, 5, { NULL }, S_HUGE_02 }, //1509
+/*S_HUGE_02*/ { SPR_HUGE, 2, 5, { NULL }, S_HUGE_03 }, //1510
+/*S_HUGE_03*/ { SPR_HUGE, 3, 5, { NULL }, S_HUGE_00 }, //1511
+/*S_STLG_00*/ { SPR_STLG, 0, -1, { NULL }, S_NULL }, //1512
+/*S_STLG_01*/ { SPR_STLG, 1, -1, { NULL }, S_NULL }, //1513
+/*S_STLG_02*/ { SPR_STLG, 2, -1, { NULL }, S_NULL }, //1514
+/*S_STLG_03*/ { SPR_STLG, 3, -1, { NULL }, S_NULL }, //1515
+/*S_STLG_04*/ { SPR_STLG, 4, -1, { NULL }, S_NULL }, //1516
+/*S_STLG_05*/ { SPR_STLG, 5, -1, { NULL }, S_NULL }, //1517
+};
+
+
+// villsa [STRIFE]
+mobjinfo_t mobjinfo[NUMMOBJTYPES] =
+{
+ { /*MT_FIELDGUARD*/
+ 25, //doomednum
+ S_TOKN_00, //spawnstate
+ 10, //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, //crashstate
+ S_XPRK_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 2*FRACUNIT, //radius
+ 1*FRACUNIT, //height
+ 10000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SHOOTABLE|MF_NOSECTOR|MF_NODIALOG, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PLAYER*/
+ -1, //doomednum
+ S_PLAY_00, //spawnstate
+ 100, //spawnhealth
+ S_PLAY_01, //seestate
+ sfx_None, //seesound
+ 0, //reactiontime
+ sfx_None, //attacksound
+ S_PLAY_07, //painstate
+ 255, //painchance
+ sfx_plpain, //painsound
+ S_NULL, //meleestate
+ S_PLAY_05, //missilestate
+ S_NULL, //crashstate
+ S_PLAY_09, //deathstate
+ S_RGIB_00, //xdeathstate
+ sfx_pldeth, //deathsound
+ 0, //speed
+ 18*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_NOTDMATCH|MF_ALLY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SHOPKEEPER_W*/
+ 116, //doomednum
+ S_MRST_00, //spawnstate
+ 10000000, //spawnhealth
+ S_MRPN_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MRPN_00, //painstate
+ 150, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 5000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH, //flags
+ "Weapon_Smith", //namepointer
+ },
+
+ { /*MT_SHOPKEEPER_B*/
+ 72, //doomednum
+ S_MRST_00, //spawnstate
+ 10000000, //spawnhealth
+ S_MRPN_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MRPN_00, //painstate
+ 150, //painchance
+ sfx_ambbar, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 5000, //mass
+ 0, //damage
+ sfx_ambppl, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH|MF_COLORSWAP1|MF_COLORSWAP3, //flags
+ "Bar_Keep", //namepointer
+ },
+
+ { /*MT_SHOPKEEPER_A*/
+ 73, //doomednum
+ S_MRST_00, //spawnstate
+ 10000000, //spawnhealth
+ S_MRPN_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MRPN_00, //painstate
+ 150, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 5000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH|MF_COLORSWAP2|MF_COLORSWAP3, //flags
+ "Armorer", //namepointer
+ },
+
+ { /*MT_SHOPKEEPER_M*/
+ 74, //doomednum
+ S_MRST_00, //spawnstate
+ 10000000, //spawnhealth
+ S_MRPN_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MRPN_00, //painstate
+ 150, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH|MF_COLORSWAP1|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ "Medic", //namepointer
+ },
+
+ { /*MT_PEASANT2_A*/
+ 3004, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 4, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT2_B*/
+ 130, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 5, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT2_C*/
+ 131, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 5, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT5_A*/
+ 65, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 7, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT5_B*/
+ 132, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 7, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT5_C*/
+ 133, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 7, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT4_A*/
+ 66, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT4_B*/
+ 134, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT4_C*/
+ 135, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT6_A*/
+ 67, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT6_B*/
+ 136, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 7, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT6_C*/
+ 137, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT3_A*/
+ 172, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT3_B*/
+ 173, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT3_C*/
+ 174, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT8_A*/
+ 175, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT8_B*/
+ 176, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT8_C*/
+ 177, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT7_A*/
+ 178, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT7_B*/
+ 179, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT7_C*/
+ 180, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PEASANT1*/
+ 181, //doomednum
+ S_PEAS_00, //spawnstate
+ 31, //spawnhealth
+ S_PEAS_01, //seestate
+ sfx_rebact, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_PEAS_12, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_PEAS_09, //meleestate
+ S_NULL, //missilestate
+ S_PEAS_14, //crashstate
+ S_PEAS_17, //deathstate
+ S_GIBS_00, //xdeathstate
+ sfx_psdtha, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL|MF_COLORSWAP1
+ |MF_COLORSWAP2|MF_COLORSWAP3, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ZOMBIE*/
+ 169, //doomednum
+ S_PEAS_25, //spawnstate
+ 31, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_AGRD_00, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_GIBS_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_psdtha, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BECOMING*/
+ 201, //doomednum
+ S_ARMR_00, //spawnstate
+ 61, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_ARMR_01, //painstate
+ 255, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_GIBS_10, //deathstate
+ S_NULL, //xdeathstate
+ sfx_psdtha, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ZOMBIESPAWNER*/
+ 170, //doomednum
+ S_PLAY_19, //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_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_telept, //activesound
+ MF_SHOOTABLE|MF_NOSECTOR, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HUGE_TANK_1*/
+ 209, //doomednum
+ S_TNK1_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HUGE_TANK_2*/
+ 210, //doomednum
+ S_TNK2_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HUGE_TANK_3*/
+ 211, //doomednum
+ S_TNK3_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TANK_4*/
+ 213, //doomednum
+ S_TNK4_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TANK_5*/
+ 214, //doomednum
+ S_TNK5_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TANK_6*/
+ 229, //doomednum
+ S_TNK6_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_KNEELING_GUY*/
+ 204, //doomednum
+ S_NEAL_00, //spawnstate
+ 51, //spawnhealth
+ S_NEAL_00, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NEAL_02, //painstate
+ 255, //painchance
+ sfx_static, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NEAL_05, //crashstate
+ S_NEAL_07, //deathstate
+ S_NULL, //xdeathstate
+ sfx_static, //deathsound
+ 0, //speed
+ 6*FRACUNIT, //radius
+ 6*FRACUNIT, //height
+ 50000, //mass
+ 0, //damage
+ sfx_chant, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BEGGAR1*/
+ 141, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_BEGGAR2*/
+ 155, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_BEGGAR3*/
+ 156, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_BEGGAR4*/
+ 157, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_BEGGAR5*/
+ 158, //doomednum
+ S_BEGR_00, //spawnstate
+ 20, //spawnhealth
+ S_BEGR_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_meatht, //attacksound
+ S_BEGR_11, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_BEGR_07, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BEGR_13, //deathstate
+ S_BEGR_22, //xdeathstate
+ sfx_psdtha, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_JUSTHIT|MF_COUNTKILL, //flags
+ "Beggar", //namepointer
+ },
+
+ { /*MT_REBEL1*/
+ 9, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL2*/
+ 144, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL3*/
+ 145, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL4*/
+ 149, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL5*/
+ 150, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_REBEL6*/
+ 151, //doomednum
+ S_HMN1_00, //spawnstate
+ 60, //spawnhealth
+ S_HMN1_11, //seestate
+ sfx_wpnup, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HMN1_22, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_HMN1_19, //missilestate
+ S_NULL, //crashstate
+ S_HMN1_24, //deathstate
+ S_RGIB_08, //xdeathstate
+ sfx_rebdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_ALLY, //flags
+ "Rebel", //namepointer
+ },
+
+ { /*MT_RLEADER*/
+ 64, //doomednum
+ S_LEDR_00, //spawnstate
+ 95, //spawnhealth
+ S_LEAD_04, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_LEAD_15, //painstate
+ 250, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_LEAD_12, //missilestate
+ S_NULL, //crashstate
+ S_LEAD_04, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOTDMATCH, //flags
+ "MACIL", //namepointer
+ },
+
+ { /*MT_RLEADER2*/
+ 200, //doomednum
+ S_LEDR_00, //spawnstate
+ 95, //spawnhealth
+ S_LEAD_04, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_LEAD_15, //painstate
+ 200, //painchance
+ sfx_pespna, //painsound
+ S_NULL, //meleestate
+ S_LEAD_17, //missilestate
+ S_NULL, //crashstate
+ S_LEAD_20, //deathstate
+ S_LEAD_20, //xdeathstate
+ sfx_slop, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_rebact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_NOTDMATCH|MF_SPECTRAL, //flags
+ "MACIL", //namepointer
+ },
+
+ { /*MT_MISSILESMOKE*/
+ -1, //doomednum
+ S_PUFY_04, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_rflite, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ 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_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_REAVER*/
+ 3001, //doomednum
+ S_ROB1_00, //spawnstate
+ 150, //spawnhealth
+ S_ROB1_02, //seestate
+ sfx_revsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_ROB1_15, //painstate
+ 128, //painchance
+ sfx_reavpn, //painsound
+ S_ROB1_10, //meleestate
+ S_ROB1_13, //missilestate
+ S_NULL, //crashstate
+ S_ROB1_17, //deathstate
+ S_ROB1_26, //xdeathstate
+ sfx_revdth, //deathsound
+ 12, //speed
+ 20*FRACUNIT, //radius
+ 60*FRACUNIT, //height
+ 500, //mass
+ 0, //damage
+ sfx_revact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_GUARD1*/
+ 3002, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac1, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD2*/
+ 142, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac2, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD3*/
+ 143, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac3, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP2, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD4*/
+ 146, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac1, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1|MF_COLORSWAP2, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD5*/
+ 147, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac2, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP3, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD6*/
+ 148, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac3, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1|MF_COLORSWAP3, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD7*/
+ 232, //doomednum
+ S_AGRD_01, //spawnstate
+ 60, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac3, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP2|MF_COLORSWAP3, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_GUARD8*/
+ 231, //doomednum
+ S_AGRD_01, //spawnstate
+ 60, //spawnhealth
+ S_AGRD_13, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_23, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac3, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL|MF_COLORSWAP1|MF_COLORSWAP2
+ |MF_COLORSWAP3, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_SHADOWGUARD*/
+ 58, //doomednum
+ S_AGRD_01, //spawnstate
+ 70, //spawnhealth
+ S_AGRD_12, //seestate
+ sfx_agrsee, //seesound
+ 8, //reactiontime
+ sfx_rifle, //attacksound
+ S_AGRD_21, //painstate
+ 150, //painchance
+ sfx_agrdpn, //painsound
+ S_NULL, //meleestate
+ S_AGRD_17, //missilestate
+ S_NULL, //crashstate
+ S_AGRD_24, //deathstate
+ S_GIBS_10, //xdeathstate
+ sfx_agrdth, //deathsound
+ 7, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_agrac2, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_COUNTKILL, //flags
+ "ACOLYTE", //namepointer
+ },
+
+ { /*MT_PGUARD*/
+ 3003, //doomednum
+ S_PGRD_00, //spawnstate
+ 300, //spawnhealth
+ S_PGRD_04, //seestate
+ sfx_pgrsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_PGRD_16, //painstate
+ 100, //painchance
+ sfx_pgrdpn, //painsound
+ S_PGRD_12, //meleestate
+ S_PGRD_14, //missilestate
+ S_NULL, //crashstate
+ S_PGRD_18, //deathstate
+ S_NULL, //xdeathstate
+ sfx_pgrdth, //deathsound
+ 8, //speed
+ 20*FRACUNIT, //radius
+ 60*FRACUNIT, //height
+ 500, //mass
+ 0, //damage
+ sfx_pgract, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_COUNTKILL, //flags
+ "TEMPLAR", //namepointer
+ },
+
+ { /*MT_CRUSADER*/
+ 3005, //doomednum
+ S_ROB2_00, //spawnstate
+ 400, //spawnhealth
+ S_ROB2_01, //seestate
+ sfx_rb2see, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_ROB2_19, //painstate
+ 128, //painchance
+ sfx_rb2pn, //painsound
+ S_NULL, //meleestate
+ S_ROB2_09, //missilestate
+ S_NULL, //crashstate
+ S_ROB2_20, //deathstate
+ S_NULL, //xdeathstate
+ sfx_rb2dth, //deathsound
+ 8, //speed
+ 40*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 400, //mass
+ 0, //damage
+ sfx_rb2act, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BISHOP*/
+ 187, //doomednum
+ S_MLDR_00, //spawnstate
+ 500, //spawnhealth
+ S_MLDR_01, //seestate
+ sfx_rb2see, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_MLDR_11, //painstate
+ 128, //painchance
+ sfx_rb2pn, //painsound
+ S_NULL, //meleestate
+ S_MLDR_09, //missilestate
+ S_NULL, //crashstate
+ S_MLDR_12, //deathstate
+ S_NULL, //xdeathstate
+ sfx_pgrdth, //deathsound
+ 8, //speed
+ 40*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 500, //mass
+ 0, //damage
+ sfx_rb2act, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL
+ |MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ORACLE*/
+ 199, //doomednum
+ S_ORCL_00, //spawnstate
+ 1, //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, //crashstate
+ S_ORCL_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_COUNTKILL|MF_NOTDMATCH, //flags
+ "ORACLE", //namepointer
+ },
+
+ { /*MT_PRIEST*/
+ 12, //doomednum
+ S_PRST_00, //spawnstate
+ 800, //spawnhealth
+ S_PRST_02, //seestate
+ sfx_lorsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_lorpn, //painsound
+ S_PRST_10, //meleestate
+ S_PRST_13, //missilestate
+ S_NULL, //crashstate
+ S_PDED_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_slop, //deathsound
+ 10, //speed
+ 15*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_tend, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST|MF_FLOAT
+ |MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL|MF_NOTDMATCH, //flags
+ "PRIEST", //namepointer
+ },
+
+ { /*MT_SPECTRE_A*/
+ 129, //doomednum
+ S_ALN1_00, //spawnstate
+ 1000, //spawnhealth
+ S_ALN1_02, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_19, //painstate
+ 250, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_13, //meleestate
+ S_ALN1_16, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 64*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_NODE*/
+ -1, //doomednum
+ S_NODE_00, //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, //crashstate
+ 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_NOCLIP|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTREHEAD*/
+ -1, //doomednum
+ S_MTHD_00, //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, //crashstate
+ 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_NOCLIP|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTRE_B*/
+ 75, //doomednum
+ S_ALN1_00, //spawnstate
+ 1200, //spawnhealth
+ S_ALN1_02, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_19, //painstate
+ 50, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_13, //meleestate
+ S_ALN1_20, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTRE_C*/
+ 76, //doomednum
+ S_ALN1_23, //spawnstate
+ 1500, //spawnhealth
+ S_ALN1_34, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_51, //painstate
+ 50, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_45, //meleestate
+ S_ALN1_48, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTRE_D*/
+ 167, //doomednum
+ S_ALN1_00, //spawnstate
+ 1700, //spawnhealth
+ S_ALN1_02, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_19, //painstate
+ 50, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_13, //meleestate
+ S_ALN1_52, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPECTRE_E*/
+ 168, //doomednum
+ S_ALN1_00, //spawnstate
+ 2000, //spawnhealth
+ S_ALN1_02, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_ALN1_19, //painstate
+ 50, //painchance
+ sfx_alnpn, //painsound
+ S_ALN1_13, //meleestate
+ S_ALN1_55, //missilestate
+ S_NULL, //crashstate
+ S_AL1P_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 12, //speed
+ 24*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ENTITY*/
+ 128, //doomednum
+ S_MNAM_00, //spawnstate
+ 2500, //spawnhealth
+ S_MNAL_02, //seestate
+ sfx_mnalse, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_MNAL_19, //painstate
+ 255, //painchance
+ sfx_alnpn, //painsound
+ S_MNAL_13, //meleestate
+ S_MNAL_16, //missilestate
+ S_NULL, //crashstate
+ S_MNAL_20, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mnaldt, //deathsound
+ 13, //speed
+ 130*FRACUNIT, //radius
+ 200*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SUBENTITY*/
+ -1, //doomednum
+ S_MNAL_27, //spawnstate
+ 990, //spawnhealth
+ S_MNAL_28, //seestate
+ sfx_alnsee, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_MNAL_40, //painstate
+ 255, //painchance
+ sfx_alnpn, //painsound
+ S_MNAL_34, //meleestate
+ S_MNAL_37, //missilestate
+ S_NULL, //crashstate
+ S_MDTH_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_alndth, //deathsound
+ 14, //speed
+ 130*FRACUNIT, //radius
+ 200*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_alnact, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_SHADOW|MF_COUNTKILL|MF_NOTDMATCH
+ |MF_MVIS|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_NEST*/
+ 26, //doomednum
+ S_NEST_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 84*FRACUNIT, //radius
+ 47*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_POD*/
+ 198, //doomednum
+ S_PODD_00, //spawnstate
+ 1000, //spawnhealth
+ S_PODD_01, //seestate
+ sfx_slop, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 25*FRACUNIT, //radius
+ 91*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_B_SHOT*/
+ -1, //doomednum
+ S_ZAP6_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 70, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_SB_SHOT*/
+ -1, //doomednum
+ S_ZAP6_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 20, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_C_SHOT*/
+ -1, //doomednum
+ S_ZOT3_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 70, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_SC_SHOT*/
+ -1, //doomednum
+ S_ZOT3_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 20, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_E_OFFSHOOT*/
+ -1, //doomednum
+ S_ZAP6_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 30*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_TRAIL*/
+ -1, //doomednum
+ S_ZAP6_03, //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, //crashstate
+ 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_DROPOFF, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_E_SHOT*/
+ -1, //doomednum
+ S_ZAP7_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 18*FRACUNIT, //speed
+ 20*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 130, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_SE_SHOT*/
+ -1, //doomednum
+ S_ZAP7_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 18*FRACUNIT, //speed
+ 20*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 30, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_A_ZAP_LEFT*/
+ -1, //doomednum
+ S_ZOT1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_06, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 22*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 100, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_A_ZAP_RIGHT*/
+ -1, //doomednum
+ S_ZOT1_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_06, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 22*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 50, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_A_GROUND*/
+ -1, //doomednum
+ S_ZAP5_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 70, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 18*FRACUNIT, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_D_SHOT*/
+ -1, //doomednum
+ S_ZOT2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 28*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 120, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SIGIL_SD_SHOT*/
+ -1, //doomednum
+ S_ZOT2_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_sigil, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sglhit, //deathsound
+ 28*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 60, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE|MF_SPECTRAL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SENTINEL*/
+ 3006, //doomednum
+ S_SEWR_00, //spawnstate
+ 100, //spawnhealth
+ S_SEWR_01, //seestate
+ sfx_sntsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_SEWR_06, //painstate
+ 255, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_SEWR_03, //missilestate
+ S_NULL, //crashstate
+ S_SEWR_07, //deathstate
+ S_NULL, //xdeathstate
+ sfx_sntdth, //deathsound
+ 7, //speed
+ 23*FRACUNIT, //radius
+ 53*FRACUNIT, //height
+ 300, //mass
+ 0, //damage
+ sfx_sntact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_SPAWNCEILING|MF_NOGRAVITY|MF_GIVEQUEST
+ |MF_FLOAT|MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_STALKER*/
+ 186, //doomednum
+ S_SPID_00, //spawnstate
+ 80, //spawnhealth
+ S_SPID_03, //seestate
+ sfx_spisit, //seesound
+ 8, //reactiontime
+ sfx_spdatk, //attacksound
+ S_SPID_24, //painstate
+ 40, //painchance
+ sfx_spdatk, //painsound
+ S_SPID_09, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_SPID_25, //deathstate
+ S_NULL, //xdeathstate
+ sfx_spidth, //deathsound
+ 16, //speed
+ 31*FRACUNIT, //radius
+ 25*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_spisit, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_SPAWNCEILING|MF_NOGRAVITY|MF_DROPOFF
+ |MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_INQUISITOR*/
+ 16, //doomednum
+ S_ROB3_00, //spawnstate
+ 1000, //spawnhealth
+ S_ROB3_02, //seestate
+ sfx_inqsee, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_ROB3_10, //missilestate
+ S_NULL, //crashstate
+ S_ROB3_20, //deathstate
+ S_NULL, //xdeathstate
+ sfx_inqdth, //deathsound
+ 12, //speed
+ 40*FRACUNIT, //radius
+ 110*FRACUNIT, //height
+ 1000, //mass
+ 0, //damage
+ sfx_inqact, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_NOBLOOD|MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_INQARM*/
+ -1, //doomednum
+ S_RBB3_05, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 25, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOCLIP|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PROGRAMMER*/
+ 71, //doomednum
+ S_PRGR_00, //spawnstate
+ 1100, //spawnhealth
+ S_PRGR_02, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_revbld, //attacksound
+ S_PRGR_18, //painstate
+ 50, //painchance
+ sfx_prgpn, //painsound
+ S_PRGR_10, //meleestate
+ S_PRGR_14, //missilestate
+ S_NULL, //crashstate
+ S_PRGR_20, //deathstate
+ S_NULL, //xdeathstate
+ sfx_rb2dth, //deathsound
+ 26, //speed
+ 45*FRACUNIT, //radius
+ 60*FRACUNIT, //height
+ 800, //mass
+ 4, //damage
+ sfx_progac, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST|MF_FLOAT
+ |MF_NOBLOOD|MF_COUNTKILL|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PROGRAMMERBASE*/
+ -1, //doomednum
+ S_BASE_00, //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, //crashstate
+ 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_NOCLIP|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HOOKSHOT*/
+ -1, //doomednum
+ S_OCLW_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_chain, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_CCLW_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 20*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 14*FRACUNIT, //height
+ 100, //mass
+ 2, //damage
+ sfx_swish, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CHAINSHOT*/
+ -1, //doomednum
+ S_TEND_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_tend, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_MINIMISSLE*/
+ -1, //doomednum
+ S_MICR_00, //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_NULL, //crashstate
+ S_MISL_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mislht, //deathsound
+ 20*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 14*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_C_MISSILE*/
+ -1, //doomednum
+ S_MICR_00, //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_NULL, //crashstate
+ S_MISL_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mislht, //deathsound
+ 20*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 14*FRACUNIT, //height
+ 100, //mass
+ 7, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SEEKMISSILE*/
+ -1, //doomednum
+ S_MISS_00, //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_NULL, //crashstate
+ S_MISL_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mislht, //deathsound
+ 20*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 14*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ELECARROW*/
+ -1, //doomednum
+ S_AROW_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_swish, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_ZAP1_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_firxpl, //deathsound
+ 30*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 10*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_swish, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_POISARROW*/
+ -1, //doomednum
+ S_ARWP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_swish, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_AROW_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 30*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 10*FRACUNIT, //height
+ 100, //mass
+ 500, //damage
+ sfx_swish, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_R_LASER*/
+ -1, //doomednum
+ S_SHT1_00, //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, //crashstate
+ S_POW1_09, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 40*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 8*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_L_LASER*/
+ -1, //doomednum
+ S_SHT1_00, //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_NULL, //crashstate
+ S_POW1_05, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 40*FRACUNIT, //speed
+ 10*FRACUNIT, //radius
+ 8*FRACUNIT, //height
+ 100, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_HEGRENADE*/
+ -1, //doomednum
+ S_GRAP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_phoot, //seesound
+ 30, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BNG4_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 15*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 13*FRACUNIT, //height
+ 20, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PGRENADE*/
+ -1, //doomednum
+ S_GRIN_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_phoot, //seesound
+ 40, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BNG3_08, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 15*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 13*FRACUNIT, //height
+ 20, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_INQGRENADE*/
+ -1, //doomednum
+ S_UBAM_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_phoot, //seesound
+ 15, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_BNG2_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 25*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 13*FRACUNIT, //height
+ 15, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PFLAME*/
+ -1, //doomednum
+ S_BNG3_09, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 120, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_FLBE_07, //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
+ NULL, //namepointer
+ },
+
+ { /*MT_TORPEDO*/
+ -1, //doomednum
+ S_TORP_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_protfl, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_THIT_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 20*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 8*FRACUNIT, //height
+ 100, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TORPEDOSPREAD*/
+ -1, //doomednum
+ S_TWAV_00, //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, //crashstate
+ S_TWAV_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 35*FRACUNIT, //speed
+ 13*FRACUNIT, //radius
+ 13*FRACUNIT, //height
+ 100, //mass
+ 10, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SFIREBALL*/
+ -1, //doomednum
+ S_FRBL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_flburn, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_FRBL_03, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 15*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 11*FRACUNIT, //height
+ 10, //mass
+ 4, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_C_FLAME*/
+ -1, //doomednum
+ S_FRBL_00, //spawnstate
+ 1000, //spawnhealth
+ S_NULL, //seestate
+ sfx_flburn, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_FRBL_03, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 35*FRACUNIT, //speed
+ 8*FRACUNIT, //radius
+ 11*FRACUNIT, //height
+ 50, //mass
+ 1, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_DROPOFF|MF_MISSILE, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_STRIFEPUFF3*/
+ -1, //doomednum
+ S_SHT2_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_STRIFEPUFF*/
+ -1, //doomednum
+ S_PUFY_00, //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, //crashstate
+ 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_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_SPARKPUFF*/
+ -1, //doomednum
+ S_POW3_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_BLOOD_DEATH*/
+ -1, //doomednum
+ S_SPRY_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TFOG*/
+ -1, //doomednum
+ S_TFOG_00, //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, //crashstate
+ 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_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_IFOG*/
+ -1, //doomednum
+ S_IFOG_00, //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, //crashstate
+ 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_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*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, //crashstate
+ 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_NOSECTOR|MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_01*/
+ 24, //doomednum
+ S_KLAX_00, //spawnstate
+ 1000, //spawnhealth
+ S_KLAX_01, //seestate
+ sfx_None, //seesound
+ 60, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ 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_STAND|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TURRET*/
+ 27, //doomednum
+ S_TURT_00, //spawnstate
+ 125, //spawnhealth
+ S_TURT_01, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_TURT_02, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_NULL, //meleestate
+ S_TURT_02, //missilestate
+ S_NULL, //crashstate
+ S_BALL_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_mislht, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 10000000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SHOOTABLE|MF_STAND|MF_SPAWNCEILING|MF_NOGRAVITY|MF_NOBLOOD
+ |MF_COUNTKILL, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_GATE*/
+ 45, //doomednum
+ S_PSTN_00, //spawnstate
+ 100, //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, //crashstate
+ S_PSTN_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 16, //speed
+ 20*FRACUNIT, //radius
+ 76*FRACUNIT, //height
+ 10000000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_GIVEQUEST|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_COMPUTER*/
+ 182, //doomednum
+ S_SECR_00, //spawnstate
+ 80, //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, //crashstate
+ S_SECR_04, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 27, //speed
+ 26*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100000, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_GIVEQUEST|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_INV_MED1*/
+ 2011, //doomednum
+ S_STMP_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 20, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Med_patch", //namepointer
+ },
+
+ { /*MT_INV_MED2*/
+ 2012, //doomednum
+ S_MDKT_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 15, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Medical_kit", //namepointer
+ },
+
+ { /*MT_INV_MED3*/
+ 83, //doomednum
+ S_FULL_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 5, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Surgery_Kit", //namepointer
+ },
+
+ { /*MT_DEGNINORE*/
+ 59, //doomednum
+ S_XPRK_01, //spawnstate
+ 10, //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, //crashstate
+ S_XPRK_02, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 10, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags
+ "Degnin_Ore", //namepointer
+ },
+
+ { /*MT_INV_ARMOR2*/
+ 2019, //doomednum
+ S_ARM1_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 3, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Metal_Armor", //namepointer
+ },
+
+ { /*MT_INV_ARMOR1*/
+ 2018, //doomednum
+ S_ARM2_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 5, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Leather_Armor", //namepointer
+ },
+
+ { /*MT_MISC_22*/
+ 2014, //doomednum
+ S_WATR_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_11*/
+ 164, //doomednum
+ S_MUGG_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_KEY_BASE*/
+ 230, //doomednum
+ S_FUSL_00, //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, //crashstate
+ 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
+ "Base_Key", //namepointer
+ },
+
+ { /*MT_GOVSKEY*/
+ -1, //doomednum
+ S_REBL_00, //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, //crashstate
+ 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
+ "Govs_Key", //namepointer
+ },
+
+ { /*MT_KEY_TRAVEL*/
+ 185, //doomednum
+ S_TPAS_00, //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, //crashstate
+ 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
+ "Passcard", //namepointer
+ },
+
+ { /*MT_KEY_ID_BLUE*/
+ 184, //doomednum
+ S_CRD1_00, //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, //crashstate
+ 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
+ "ID_Badge", //namepointer
+ },
+
+ { /*MT_PRISONKEY*/
+ -1, //doomednum
+ S_PRIS_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 11, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags
+ "Prison_Key", //namepointer
+ },
+
+ { /*MT_KEY_HAND*/
+ 91, //doomednum
+ S_HAND_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 12, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags
+ "Severed_Hand", //namepointer
+ },
+
+ { /*MT_POWER1KEY*/
+ -1, //doomednum
+ S_PWR1_00, //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, //crashstate
+ 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
+ "Power1_Key", //namepointer
+ },
+
+ { /*MT_POWER2KEY*/
+ -1, //doomednum
+ S_PWR2_00, //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, //crashstate
+ 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
+ "Power2_Key", //namepointer
+ },
+
+ { /*MT_POWER3KEY*/
+ -1, //doomednum
+ S_PWR3_00, //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, //crashstate
+ 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
+ "Power3_Key", //namepointer
+ },
+
+ { /*MT_KEY_GOLD*/
+ 40, //doomednum
+ S_KY1G_00, //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, //crashstate
+ 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
+ "Gold_Key", //namepointer
+ },
+
+ { /*MT_KEY_ID_GOLD*/
+ 13, //doomednum
+ S_CRD2_00, //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, //crashstate
+ 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
+ "ID_Card", //namepointer
+ },
+
+ { /*MT_KEY_SILVER*/
+ 38, //doomednum
+ S_KY2S_00, //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, //crashstate
+ 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
+ "Silver_Key", //namepointer
+ },
+
+ { /*MT_KEY_ORACLE*/
+ 61, //doomednum
+ S_ORAC_00, //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, //crashstate
+ 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
+ "Oracle_Key", //namepointer
+ },
+
+ { /*MT_MILITARYID*/
+ -1, //doomednum
+ S_GYID_00, //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, //crashstate
+ 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
+ "Military_ID", //namepointer
+ },
+
+ { /*MT_KEY_ORDER*/
+ 86, //doomednum
+ S_FUBR_00, //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, //crashstate
+ 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
+ "Order_Key", //namepointer
+ },
+
+ { /*MT_KEY_WAREHOUSE*/
+ 166, //doomednum
+ S_WARE_00, //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, //crashstate
+ 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
+ "Warehouse_Key", //namepointer
+ },
+
+ { /*MT_KEY_BRASS*/
+ 39, //doomednum
+ S_KY3B_00, //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, //crashstate
+ 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
+ "Brass_Key", //namepointer
+ },
+
+ { /*MT_KEY_RED_CRYSTAL*/
+ 192, //doomednum
+ S_RCRY_00, //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, //crashstate
+ 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
+ "Red_Crystal_Key", //namepointer
+ },
+
+ { /*MT_KEY_BLUE_CRYSTAL*/
+ 193, //doomednum
+ S_BCRY_00, //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, //crashstate
+ 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
+ "Blue_Crystal_Key", //namepointer
+ },
+
+ { /*MT_KEY_CHAPEL*/
+ 195, //doomednum
+ S_CHAP_00, //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, //crashstate
+ 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
+ "Chapel_Key", //namepointer
+ },
+
+ { /*MT_CATACOMBKEY*/
+ -1, //doomednum
+ S_TUNL_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 28, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags
+ "Catacomb_Key", //namepointer
+ },
+
+ { /*MT_SECURITYKEY*/
+ -1, //doomednum
+ S_SECK_00, //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, //crashstate
+ 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
+ "Security_Key", //namepointer
+ },
+
+ { /*MT_KEY_CORE*/
+ 236, //doomednum
+ S_GOID_00, //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, //crashstate
+ 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
+ "Core_Key", //namepointer
+ },
+
+ { /*MT_KEY_MAULER*/
+ 233, //doomednum
+ S_BLTK_00, //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, //crashstate
+ 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
+ "Mauler_Key", //namepointer
+ },
+
+ { /*MT_KEY_FACTORY*/
+ 234, //doomednum
+ S_PROC_00, //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, //crashstate
+ 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
+ "Factory_Key", //namepointer
+ },
+
+ { /*MT_KEY_MINE*/
+ 235, //doomednum
+ S_MINE_00, //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, //crashstate
+ 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
+ "MINE_KEY", //namepointer
+ },
+
+ { /*MT_NEWKEY5*/
+ -1, //doomednum
+ S_BLTK_00, //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, //crashstate
+ 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
+ "New_Key5", //namepointer
+ },
+
+ { /*MT_INV_SHADOWARMOR*/
+ 2024, //doomednum
+ S_SHD1_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 2, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Shadow_armor", //namepointer
+ },
+
+ { /*MT_INV_SUIT*/
+ 2025, //doomednum
+ S_MASK_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 5, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Environmental_Suit", //namepointer
+ },
+
+ { /*MT_QUEST_UNIFORM*/
+ 90, //doomednum
+ S_UNIF_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 15, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST, //flags
+ "Guard_Uniform", //namepointer
+ },
+
+ { /*MT_QUEST_GUARD_UNIFORM*/
+ 52, //doomednum
+ S_OFIC_00, //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, //crashstate
+ 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
+ "Officer's_Uniform", //namepointer
+ },
+
+ { /*MT_INV_SUPERMAP*/
+ 2026, //doomednum
+ S_PMAP_00, //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, //crashstate
+ 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
+ "map", //namepointer
+ },
+
+ { /*MT_INV_RADAR*/
+ 2027, //doomednum
+ S_PMUP_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 1, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "scanner", //namepointer
+ },
+
+ { /*MT_BEACON*/
+ 10, //doomednum
+ S_BEAC_00, //spawnstate
+ 5, //spawnhealth
+ S_BEAC_01, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 3, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_DROPPED, //flags
+ "Teleporter_Beacon", //namepointer
+ },
+
+ { /*MT_INV_TARGETER*/
+ 207, //doomednum
+ S_TARG_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 5, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL, //flags
+ "Targeter", //namepointer
+ },
+
+ { /*MT_MONY_1*/
+ 93, //doomednum
+ S_COIN_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 2147483647, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_DROPPED|MF_NOTDMATCH, //flags
+ "coin", //namepointer
+ },
+
+ { /*MT_MONY_10*/
+ 138, //doomednum
+ S_CRED_00, //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, //crashstate
+ 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_DROPPED|MF_NOTDMATCH, //flags
+ "10_gold", //namepointer
+ },
+
+ { /*MT_MONY_25*/
+ 139, //doomednum
+ S_SACK_00, //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, //crashstate
+ 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_DROPPED|MF_NOTDMATCH, //flags
+ "25_gold", //namepointer
+ },
+
+ { /*MT_MONY_50*/
+ 140, //doomednum
+ S_CHST_00, //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, //crashstate
+ 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_DROPPED|MF_NOTDMATCH, //flags
+ "50_gold", //namepointer
+ },
+
+ { /*MT_MONY_300*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 3, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_DROPPED, //flags
+ "300_gold", //namepointer
+ },
+
+ { /*MT_TOKEN_RING*/
+ -1, //doomednum
+ S_RING_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 1, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_NOTDMATCH, //flags
+ "ring", //namepointer
+ },
+
+ { /*MT_INV_CHALICE*/
+ 205, //doomednum
+ S_RELC_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 2, //speed
+ 10*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_DROPPED, //flags
+ "Offering_Chalice", //namepointer
+ },
+
+ { /*MT_TOKEN_EAR*/
+ -1, //doomednum
+ S_EARS_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 9, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST, //flags
+ "ear", //namepointer
+ },
+
+ { /*MT_INV_COMMUNICATOR*/
+ 206, //doomednum
+ S_COMM_00, //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, //crashstate
+ 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
+ "Communicator", //namepointer
+ },
+
+ { /*MT_AGREN*/
+ 152, //doomednum
+ S_GRN1_00, //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, //crashstate
+ 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
+ "HE-Grenade_Rounds", //namepointer
+ },
+
+ { /*MT_APGREN*/
+ 153, //doomednum
+ S_GRN2_00, //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, //crashstate
+ 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
+ "Phosphorus-Grenade_Rounds", //namepointer
+ },
+
+ { /*MT_ACLIP*/
+ 2007, //doomednum
+ S_BLIT_00, //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, //crashstate
+ 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
+ "clip_of_bullets", //namepointer
+ },
+
+ { /*MT_AAMMOBOX*/
+ 2048, //doomednum
+ S_BBOX_00, //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, //crashstate
+ 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
+ "ammo", //namepointer
+ },
+
+ { /*MT_AMINI*/
+ 2010, //doomednum
+ S_MSSL_00, //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, //crashstate
+ 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
+ "mini_missiles", //namepointer
+ },
+
+ { /*MT_AMINIBOX*/
+ 2046, //doomednum
+ S_ROKT_00, //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, //crashstate
+ 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
+ "crate_of_missiles", //namepointer
+ },
+
+ { /*MT_ACELL*/
+ 2047, //doomednum
+ S_BRY1_00, //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, //crashstate
+ 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
+ "energy_pod", //namepointer
+ },
+
+ { /*MT_APCELL*/
+ 17, //doomednum
+ S_CPAC_00, //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, //crashstate
+ 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
+ "energy_pack", //namepointer
+ },
+
+ { /*MT_APAROW*/
+ 115, //doomednum
+ S_PQRL_00, //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, //crashstate
+ 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
+ "poison_bolts", //namepointer
+ },
+
+ { /*MT_AAROW*/
+ 114, //doomednum
+ S_XQRL_00, //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, //crashstate
+ 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
+ "electric_bolts", //namepointer
+ },
+
+ { /*MT_INV_SATCHEL*/
+ 183, //doomednum
+ S_BKPK_00, //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, //crashstate
+ 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
+ "ammo_satchel", //namepointer
+ },
+
+ { /*MT_PULSE*/
+ 2002, //doomednum
+ S_RIFL_00, //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, //crashstate
+ 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
+ "assault_gun", //namepointer
+ },
+
+ { /*MT_RIFLESTAND*/
+ 2006, //doomednum
+ S_RIFL_01, //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, //crashstate
+ 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
+ "assault_gun", //namepointer
+ },
+
+ { /*MT_FLAMETHROWER*/
+ 2005, //doomednum
+ S_FLAM_00, //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, //crashstate
+ 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
+ "flame_thrower", //namepointer
+ },
+
+ { /*MT_TOKEN_FLAME_THROWER_PARTS*/
+ -1, //doomednum
+ S_BFLM_00, //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, //crashstate
+ 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
+ "flame_thrower_parts", //namepointer
+ },
+
+ { /*MT_MISSILELAUNCHER*/
+ 2003, //doomednum
+ S_MMSL_00, //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, //crashstate
+ 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
+ "mini_missile_launcher", //namepointer
+ },
+
+ { /*MT_BLASTER*/
+ 2004, //doomednum
+ S_TRPD_00, //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, //crashstate
+ 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
+ "mauler", //namepointer
+ },
+
+ { /*MT_CROSSBOW*/
+ 2001, //doomednum
+ S_CBOW_00, //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, //crashstate
+ 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
+ "crossbow", //namepointer
+ },
+
+ { /*MT_GRENADELAUNCHER*/
+ 154, //doomednum
+ S_GRND_00, //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, //crashstate
+ 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
+ "Grenade_launcher", //namepointer
+ },
+
+ { /*MT_SIGIL_A*/
+ 77, //doomednum
+ S_SIGL_00, //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, //crashstate
+ 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
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_SIGIL_B*/
+ 78, //doomednum
+ S_SIGL_01, //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, //crashstate
+ 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
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_SIGIL_C*/
+ 79, //doomednum
+ S_SIGL_02, //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, //crashstate
+ 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
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_SIGIL_D*/
+ 80, //doomednum
+ S_SIGL_03, //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, //crashstate
+ 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
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_SIGIL_E*/
+ 81, //doomednum
+ S_SIGL_04, //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, //crashstate
+ 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
+ "SIGIL", //namepointer
+ },
+
+ { /*MT_POWER_CRYSTAL*/
+ 92, //doomednum
+ S_CRYS_00, //spawnstate
+ 50, //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, //crashstate
+ S_BOOM_00, //deathstate
+ S_NULL, //xdeathstate
+ sfx_explod, //deathsound
+ 14, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 99999999, //mass
+ 0, //damage
+ sfx_reactr, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_GIVEQUEST|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RAT*/
+ 85, //doomednum
+ S_RATT_00, //spawnstate
+ 5, //spawnhealth
+ S_RATT_01, //seestate
+ sfx_ratact, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_NULL, //painstate
+ 0, //painchance
+ sfx_None, //painsound
+ S_RATT_05, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_MEAT_16, //deathstate
+ S_NULL, //xdeathstate
+ sfx_ratact, //deathsound
+ 13, //speed
+ 10*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_ratact, //activesound
+ MF_NODIALOG|MF_NOBLOOD|MF_COUNTKILL, //flags
+ "rat_buddy", //namepointer
+ },
+
+ { /*MT_MISC_05*/
+ 82, //doomednum
+ S_BARW_00, //spawnstate
+ 10, //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, //crashstate
+ S_BARW_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_wbrldt, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_06*/
+ 94, //doomednum
+ S_BART_00, //spawnstate
+ 30, //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, //crashstate
+ S_BART_01, //deathstate
+ S_NULL, //xdeathstate
+ sfx_barexp, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_15*/
+ 208, //doomednum
+ S_HOGN_00, //spawnstate
+ 99999999, //spawnhealth
+ S_NULL, //seestate
+ sfx_None, //seesound
+ 8, //reactiontime
+ sfx_None, //attacksound
+ S_HOGN_01, //painstate
+ 255, //painchance
+ sfx_mtalht, //painsound
+ S_NULL, //meleestate
+ S_NULL, //missilestate
+ S_NULL, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 9999999, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_NODIALOG|MF_NOBLOOD, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT14*/
+ 95, //doomednum
+ S_LITS_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 4*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT13*/
+ 96, //doomednum
+ S_LITB_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 4*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT12*/
+ 97, //doomednum
+ S_LITG_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 4*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT18*/
+ 2028, //doomednum
+ S_LITE_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR2*/
+ 48, //doomednum
+ S_MONI_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR3*/
+ 54, //doomednum
+ S_STEL_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR4*/
+ 55, //doomednum
+ S_STLA_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR5*/
+ 56, //doomednum
+ S_STLE_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR6*/
+ 57, //doomednum
+ S_HUGE_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 24*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR7*/
+ 227, //doomednum
+ S_APOW_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 24*FRACUNIT, //radius
+ 192*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln2, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE2*/
+ 98, //doomednum
+ S_STLG_02, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 54*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE3*/
+ 161, //doomednum
+ S_STLG_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE4*/
+ 160, //doomednum
+ S_STLG_01, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE6*/
+ 159, //doomednum
+ S_STLG_03, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE7*/
+ 162, //doomednum
+ S_STLG_04, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE5*/
+ 163, //doomednum
+ S_STLG_05, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 25*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT2*/
+ 34, //doomednum
+ S_CNDL_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT3*/
+ 35, //doomednum
+ S_CLBR_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_03*/
+ 103, //doomednum
+ S_DRIP_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_wdrip, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_13*/
+ 104, //doomednum
+ S_SPLH_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_wfall, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_02*/
+ 53, //doomednum
+ S_CDRP_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 1*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_07*/
+ 112, //doomednum
+ S_WTFT_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_wsplsh, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BIO2*/
+ 113, //doomednum
+ S_HERT_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TELEPORTSTAND*/
+ 23, //doomednum
+ S_TELP_00, //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, //crashstate
+ 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_SHADOW, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING1*/
+ 22, //doomednum
+ S_ROB2_28, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING2*/
+ 15, //doomednum
+ S_PLAY_18, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING3*/
+ 18, //doomednum
+ S_PEAS_24, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING4*/
+ 21, //doomednum
+ S_AGRD_31, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING5*/
+ 20, //doomednum
+ S_ROB1_25, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_DEADTHING6*/
+ 19, //doomednum
+ S_HMN1_31, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_BIO1*/
+ 212, //doomednum
+ S_SACR_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_GIBS*/
+ 54, //doomednum
+ S_DEAD_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_04*/
+ 70, //doomednum
+ S_BARL_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 48*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT11*/
+ 105, //doomednum
+ S_BOWL_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT10*/
+ 106, //doomednum
+ S_BRAZ_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT9*/
+ 107, //doomednum
+ S_TRCH_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 0*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT8*/
+ 108, //doomednum
+ S_TRHO_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 0*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_14*/
+ 109, //doomednum
+ S_CHAN_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 93*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT1*/
+ 28, //doomednum
+ S_CAGE_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 3*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR8*/
+ 110, //doomednum
+ S_STAT_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR9*/
+ 44, //doomednum
+ S_DSTA_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT15*/
+ 111, //doomednum
+ S_LTRH_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 4*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT4*/
+ 43, //doomednum
+ S_LAMP_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 3*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT5*/
+ 46, //doomednum
+ S_LANT_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 3*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_ROCK1*/
+ 99, //doomednum
+ S_ROK1_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_ROCK2*/
+ 100, //doomednum
+ S_ROK2_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_ROCK3*/
+ 101, //doomednum
+ S_ROK3_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_ROCK4*/
+ 102, //doomednum
+ S_ROK4_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE7*/
+ 215, //doomednum
+ S_LOGG_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_wriver, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE1*/
+ 29, //doomednum
+ S_RUB1_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE2*/
+ 30, //doomednum
+ S_RUB2_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE3*/
+ 31, //doomednum
+ S_RUB3_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE4*/
+ 32, //doomednum
+ S_RUB4_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE5*/
+ 36, //doomednum
+ S_RUB5_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE6*/
+ 37, //doomednum
+ S_RUB6_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE7*/
+ 41, //doomednum
+ S_RUB7_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_RUBBLE8*/
+ 42, //doomednum
+ S_RUB8_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_08*/
+ 117, //doomednum
+ S_CRAB_00, //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, //crashstate
+ 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_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT6*/
+ 47, //doomednum
+ S_LMPC_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT7*/
+ 50, //doomednum
+ S_LOGS_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 10*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_smfire, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE2*/
+ 51, //doomednum
+ S_TREE_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 109*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE3*/
+ 202, //doomednum
+ S_TREE_01, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 109*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE4*/
+ 203, //doomednum
+ S_TREE_02, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE1*/
+ 33, //doomednum
+ S_TRE1_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 80*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE6*/
+ 60, //doomednum
+ S_BUSH_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 15*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TREE5*/
+ 62, //doomednum
+ S_SHRB_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_CAVE1*/
+ 63, //doomednum
+ S_STAK_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 20*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR1*/
+ 69, //doomednum
+ S_BAR1_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_10*/
+ 165, //doomednum
+ S_VASE_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 12*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_09*/
+ 188, //doomednum
+ S_VASE_01, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 12*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_17*/
+ 189, //doomednum
+ S_STOL_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 6*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_18*/
+ 190, //doomednum
+ S_POT1_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_19*/
+ 191, //doomednum
+ S_TUB1_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_20*/
+ 194, //doomednum
+ S_ANVL_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 32*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT16*/
+ 196, //doomednum
+ S_TLMP_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 11*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT17*/
+ 197, //doomednum
+ S_TLMP_01, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 8*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_21*/
+ 68, //doomednum
+ S_TRAY_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 24*FRACUNIT, //radius
+ 40*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_12*/
+ 228, //doomednum
+ S_AFED_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 12*FRACUNIT, //radius
+ 24*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_26*/
+ 216, //doomednum
+ S_SBAN_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 24*FRACUNIT, //radius
+ 96*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_NOBLOCKMAP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_23*/
+ 217, //doomednum
+ S_BOTR_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_24*/
+ 218, //doomednum
+ S_HATR_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_MISC_25*/
+ 219, //doomednum
+ S_TOPR_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_COUPLING*/
+ 220, //doomednum
+ S_COUP_00, //spawnstate
+ 40, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 6, //speed
+ 17*FRACUNIT, //radius
+ 64*FRACUNIT, //height
+ 999999, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SOLID|MF_SHOOTABLE|MF_GIVEQUEST|MF_NODIALOG|MF_DROPPED
+ |MF_NOBLOOD|MF_NOTDMATCH, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_COUPLING_BROKEN*/
+ 226, //doomednum
+ S_COUP_02, //spawnstate
+ 40, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 512*FRACUNIT, //speed
+ 16*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 1, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST|MF_DROPPED, //flags
+ "BROKEN_POWER_COUPLING", //namepointer
+ },
+
+ { /*MT_PILLAR10*/
+ 221, //doomednum
+ S_BUBB_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln5, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR11*/
+ 222, //doomednum
+ S_BUBF_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln6, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR12*/
+ 223, //doomednum
+ S_BUBF_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 72*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln4, //activesound
+ MF_SOLID|MF_SPAWNCEILING|MF_NOGRAVITY, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_PILLAR13*/
+ 224, //doomednum
+ S_ASPR_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 16*FRACUNIT, //radius
+ 128*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln3, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_LIGHT19*/
+ 225, //doomednum
+ S_SPDL_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 0, //speed
+ 32*FRACUNIT, //radius
+ 56*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_amaln1, //activesound
+ MF_SOLID, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_MEAT*/
+ -1, //doomednum
+ S_MEAT_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_JUNK*/
+ -1, //doomednum
+ S_JUNK_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_BURNDROP*/
+ -1, //doomednum
+ S_FFOT_00, //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, //crashstate
+ 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_NOCLIP, //flags
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_AMMO*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "Ammo", //namepointer
+ },
+
+ { /*MT_TOKEN_HEALTH*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "Health", //namepointer
+ },
+
+ { /*MT_TOKEN*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "info", //namepointer
+ },
+
+ { /*MT_TOKEN_ALARM*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "alarm", //namepointer
+ },
+
+ { /*MT_TOKEN_DOOR1*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_SHOPCLOSE*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_PRISON_PASS*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 10, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST, //flags
+ "Prison_pass", //namepointer
+ },
+
+ { /*MT_TOKEN_DOOR3*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_STAMINA*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_NEW_ACCURACY*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_REPORT*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "report", //namepointer
+ },
+
+ { /*MT_TOKEN_TOUGHNESS*/
+ -1, //doomednum
+ S_HELT_00, //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, //crashstate
+ 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
+ "Toughness", //namepointer
+ },
+
+ { /*MT_TOKEN_ACCURACY*/
+ -1, //doomednum
+ S_GUNT_00, //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, //crashstate
+ 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
+ "Accuracy", //namepointer
+ },
+
+ { /*MT_TOKEN_ORACLE_PASS*/
+ -1, //doomednum
+ S_OTOK_00, //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, //crashstate
+ S_NULL, //deathstate
+ S_NULL, //xdeathstate
+ sfx_None, //deathsound
+ 18, //speed
+ 20*FRACUNIT, //radius
+ 16*FRACUNIT, //height
+ 100, //mass
+ 0, //damage
+ sfx_None, //activesound
+ MF_SPECIAL|MF_GIVEQUEST, //flags
+ "Oracle_Pass", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST1*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST2*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST3*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST4*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "quest4", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST5*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "quest5", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST6*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "quest6", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST7*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST8*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST9*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST10*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST11*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST12*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST13*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_CRYSTAL*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "You've_Blown_Up_the_Crystal", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST15*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_GATEQUEST*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "You've_Blown_Up_the_Gates", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST17*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST18*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST19*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST20*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_BISHOP*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "You_Killed_the_Bishop!", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST22*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_ORACLE*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "You've_Killed_The_Oracle!", //namepointer
+ },
+
+ { /*MT_TOKEN_MACIL*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "You_Killed_Macil!", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST25*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_LOREMASTER*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "You've_Killed_The_Loremaster!", //namepointer
+ },
+
+ { /*MT_SECRQUEST*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ "You've_Blown_Up_the_Computer", //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST28*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST29*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST30*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_TOKEN_QUEST31*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+ { /*MT_SLIDESHOW*/
+ -1, //doomednum
+ S_TOKN_00, //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, //crashstate
+ 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
+ NULL, //namepointer
+ },
+
+};
+
+
+
diff --git a/src/strife/info.h b/src/strife/info.h
new file mode 100644
index 00000000..dce91e00
--- /dev/null
+++ b/src/strife/info.h
@@ -0,0 +1,2227 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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"
+
+// villsa [STRIFE]
+typedef enum
+{
+ SPR_PLAY, // 0
+ SPR_PNCH, // 1
+ SPR_WAVE, // 2
+ SPR_RBPY, // 3
+ SPR_TRGT, // 4
+ SPR_XBOW, // 5
+ SPR_MMIS, // 6
+ SPR_RIFG, // 7
+ SPR_RIFF, // 8
+ SPR_FLMT, // 9
+ SPR_FLMF, // 10
+ SPR_BLST, // 11
+ SPR_BLSF, // 12
+ SPR_GREN, // 13
+ SPR_GREF, // 14
+ SPR_SIGH, // 15
+ SPR_SIGF, // 16
+ SPR_POW1, // 17
+ SPR_POW2, // 18
+ SPR_POW3, // 19
+ SPR_ZAP1, // 20
+ SPR_SPRY, // 21
+ SPR_BLOD, // 22
+ SPR_PUFY, // 23
+ SPR_SHT1, // 24
+ SPR_SHT2, // 25
+ SPR_GRIN, // 26
+ SPR_GRAP, // 27
+ SPR_UBAM, // 28
+ SPR_BNG2, // 29
+ SPR_BNG4, // 30
+ SPR_BNG3, // 31
+ SPR_FLBE, // 32
+ SPR_XPRK, // 33
+ SPR_OCLW, // 34
+ SPR_CCLW, // 35
+ SPR_TEND, // 36
+ SPR_MICR, // 37
+ SPR_MISS, // 38
+ SPR_AROW, // 39
+ SPR_ARWP, // 40
+ SPR_TORP, // 41
+ SPR_THIT, // 42
+ SPR_TWAV, // 43
+ SPR_MISL, // 44
+ SPR_TFOG, // 45
+ SPR_IFOG, // 46
+ SPR_SHRD, // 47
+ SPR_RGIB, // 48
+ SPR_MRYS, // 49
+ SPR_MRNO, // 50
+ SPR_MRST, // 51
+ SPR_MRLK, // 52
+ SPR_MRBD, // 53
+ SPR_MRPN, // 54
+ SPR_MRGT, // 55
+ SPR_BURN, // 56
+ SPR_DISR, // 57
+ SPR_PEAS, // 58
+ SPR_GIBS, // 59
+ SPR_AGRD, // 60
+ SPR_ARMR, // 61
+ SPR_SACR, // 62
+ SPR_TNK1, // 63
+ SPR_TNK2, // 64
+ SPR_TNK3, // 65
+ SPR_TNK4, // 66
+ SPR_TNK5, // 67
+ SPR_TNK6, // 68
+ SPR_NEAL, // 69
+ SPR_BEGR, // 70
+ SPR_HMN1, // 71
+ SPR_LEDR, // 72
+ SPR_LEAD, // 73
+ SPR_ROB1, // 74
+ SPR_PGRD, // 75
+ SPR_ROB2, // 76
+ SPR_MLDR, // 77
+ SPR_ORCL, // 78
+ SPR_PRST, // 79
+ SPR_PDED, // 80
+ SPR_ALN1, // 81
+ SPR_AL1P, // 82
+ SPR_NODE, // 83
+ SPR_MTHD, // 84
+ SPR_MNAM, // 85
+ SPR_MNAL, // 86
+ SPR_MDTH, // 87
+ SPR_NEST, // 88
+ SPR_PODD, // 89
+ SPR_ZAP6, // 90
+ SPR_ZOT3, // 91
+ SPR_ZAP7, // 92
+ SPR_ZOT1, // 93
+ SPR_ZAP5, // 94
+ SPR_ZOT2, // 95
+ SPR_SEWR, // 96
+ SPR_SPID, // 97
+ SPR_ROB3, // 98
+ SPR_RBB3, // 99
+ SPR_PRGR, // 100
+ SPR_BASE, //
+ SPR_FRBL, //
+ SPR_KLAX, //
+ SPR_TURT, //
+ SPR_BALL, // 105
+ SPR_PSTN, //
+ SPR_SECR, //
+ SPR_TARG, //
+ SPR_RING, //
+ SPR_EARS, // 110
+ SPR_COMM, //
+ SPR_BOOM, //
+ SPR_RATT, //
+ SPR_HOGN, //
+ SPR_DEAD, // 115
+ SPR_SBAN, //
+ SPR_BOTR, //
+ SPR_HATR, //
+ SPR_TOPR, //
+ SPR_COUP, // 120
+ SPR_BUBB, //
+ SPR_BUBF, //
+ SPR_BUBC, //
+ SPR_ASPR, //
+ SPR_SPDL, // 125
+ SPR_TOKN, //
+ SPR_OTOK, //
+ SPR_HELT, //
+ SPR_GUNT, //
+ SPR_FULL, // 130
+ SPR_MEAT, //
+ SPR_JUNK, //
+ SPR_FFOT, //
+ SPR_DIE1, //
+ SPR_BEAC, // 135
+ SPR_ARM1, //
+ SPR_ARM2, //
+ SPR_BARW, //
+ SPR_BART, //
+ SPR_LAMP, // 140
+ SPR_LANT, //
+ SPR_BARL, //
+ SPR_BOWL, //
+ SPR_BRAZ, //
+ SPR_TRCH, // 145
+ SPR_LTRH, //
+ SPR_LMPC, //
+ SPR_LOGS, //
+ SPR_TRHO, //
+ SPR_WATR, // 150
+ SPR_MUGG, //
+ SPR_FUSL, //
+ SPR_CRD1, //
+ SPR_CRD2, //
+ SPR_TPAS, // 155
+ SPR_KY1G, //
+ SPR_KY2S, //
+ SPR_KY3B, //
+ SPR_HAND, //
+ SPR_CRYS, // 160
+ SPR_PRIS, //
+ SPR_PWR1, //
+ SPR_PWR2, //
+ SPR_PWR3, //
+ SPR_ORAC, // 165
+ SPR_GYID, //
+ SPR_FUBR, //
+ SPR_WARE, //
+ SPR_RCRY, //
+ SPR_BCRY, // 170
+ SPR_CHAP, //
+ SPR_TUNL, //
+ SPR_BLTK, //
+ SPR_SECK, //
+ SPR_MINE, // 175
+ SPR_REBL, //
+ SPR_PROC, //
+ SPR_ANKH, //
+ SPR_GOID, //
+ SPR_STMP, // 180
+ SPR_MDKT, //
+ SPR_COIN, //
+ SPR_CRED, //
+ SPR_SACK, //
+ SPR_CHST, // 185
+ SPR_SHD1, //
+ SPR_MASK, //
+ SPR_UNIF, //
+ SPR_OFIC, //
+ SPR_PMAP, // 190
+ SPR_PMUP, //
+ SPR_BLIT, //
+ SPR_BBOX, //
+ SPR_MSSL, //
+ SPR_ROKT, // 195
+ SPR_BRY1, //
+ SPR_CPAC, //
+ SPR_PQRL, //
+ SPR_XQRL, //
+ SPR_GRN1, // 200
+ SPR_GRN2, //
+ SPR_BKPK, //
+ SPR_RELC, //
+ SPR_RIFL, //
+ SPR_FLAM, // 205
+ SPR_BFLM, //
+ SPR_MMSL, //
+ SPR_TRPD, //
+ SPR_GRND, //
+ SPR_CBOW, // 210
+ SPR_SIGL, //
+ SPR_LITE, //
+ SPR_CNDL, //
+ SPR_CLBR, //
+ SPR_LITS, // 215
+ SPR_LITB, //
+ SPR_LITG, //
+ SPR_ROK1, //
+ SPR_ROK2, //
+ SPR_ROK3, // 220
+ SPR_ROK4, //
+ SPR_LOGG, //
+ SPR_RUB1, //
+ SPR_RUB2, //
+ SPR_RUB3, // 225
+ SPR_RUB4, //
+ SPR_RUB5, //
+ SPR_RUB6, //
+ SPR_RUB7, //
+ SPR_RUB8, // 230
+ SPR_CHAN, //
+ SPR_STAT, //
+ SPR_DSTA, //
+ SPR_CRAB, //
+ SPR_CAGE, // 235
+ SPR_TREE, //
+ SPR_TRE1, //
+ SPR_BUSH, //
+ SPR_SHRB, //
+ SPR_STAK, // 240
+ SPR_BAR1, //
+ SPR_VASE, //
+ SPR_STOL, //
+ SPR_POT1, //
+ SPR_TUB1, // 245
+ SPR_ANVL, //
+ SPR_TLMP, //
+ SPR_TRAY, //
+ SPR_APOW, //
+ SPR_AFED, // 250
+ SPR_DRIP, //
+ SPR_CDRP, //
+ SPR_SPLH, //
+ SPR_WTFT, //
+ SPR_HERT, //
+ SPR_TELP, //
+ SPR_MONI, //
+ SPR_STEL, //
+ SPR_STLA, //
+ SPR_STLE, // 260
+ SPR_HUGE, // 261
+ SPR_STLG, // 262
+ NUMSPRITES
+
+} spritenum_t;
+
+// villsa [STRIFE]
+typedef enum
+{
+ S_NULL, // 00
+ S_PNCH_00, // 01
+ S_WAVE_00, // 02
+ S_WAVE_01, // 03
+ S_WAVE_02, // 04
+ S_WAVE_03, // 05
+ S_RBPY_00, // 06
+ S_RBPY_01, // 07
+ S_RBPY_02, // 08
+ S_RBPY_03, // 09
+ S_TRGT_00, // 10
+ S_TRGT_01, // 11
+ S_TRGT_02, // 12
+ S_PNCH_01, // 13
+ S_PNCH_02, // 14
+ S_PNCH_03, // 15
+ S_PNCH_04, // 16
+ S_PNCH_05, // 17
+ S_PNCH_06, // 18
+ S_PNCH_07, // 19
+ S_PNCH_08, // 20
+ S_XBOW_00, // 21
+ S_XBOW_01, // 22
+ S_XBOW_02, // 23
+ S_XBOW_03, // 24
+ S_XBOW_04, // 25
+ S_XBOW_05, // 26
+ S_XBOW_06, // 27
+ S_XBOW_07, // 28
+ S_XBOW_08, // 29
+ S_XBOW_09, // 30
+ S_XBOW_10, // 31
+ S_XBOW_11, // 32
+ S_XBOW_12, // 33
+ S_XBOW_13, // 34
+ S_XBOW_14, // 35
+ S_XBOW_15, // 36
+ S_XBOW_16, // 37
+ S_XBOW_17, // 38
+ S_XBOW_18, // 39
+ S_XBOW_19, // 40
+ S_XBOW_20, // 41
+ S_XBOW_21, // 42
+ S_XBOW_22, // 43
+ S_MMIS_00, // 44
+ S_MMIS_01, // 45
+ S_MMIS_02, // 46
+ S_MMIS_03, // 47
+ S_MMIS_04, // 48
+ S_MMIS_05, // 49
+ S_MMIS_06, // 50
+ S_MMIS_07, // 51
+ S_MMIS_08, // 52
+ S_MMIS_09, // 53
+ S_RIFG_00, // 54
+ S_RIFG_01, // 55
+ S_RIFG_02, // 56
+ S_RIFF_00, // 57
+ S_RIFF_01, // 58
+ S_RIFG_03, // 59
+ S_RIFG_04, // 60
+ S_RIFG_05, // 61
+ S_FLMT_00, // 62
+ S_FLMT_01, // 63
+ S_FLMT_02, // 64
+ S_FLMT_03, // 65
+ S_FLMF_00, // 66
+ S_FLMF_01, // 67
+ S_BLST_00, // 68
+ S_BLST_01, // 69
+ S_BLST_02, // 70
+ S_BLST_03, // 71
+ S_BLST_04, // 72
+ S_BLST_05, // 73
+ S_BLSF_00, // 74
+ S_BLST_06, // 75
+ S_BLST_07, // 76
+ S_BLST_08, // 77
+ S_BLST_09, // 78
+ S_BLST_10, // 79
+ S_BLST_11, // 80
+ S_BLST_12, // 81
+ S_BLST_13, // 82
+ S_BLST_14, // 83
+ S_BLST_15, // 84
+ S_BLST_16, // 85
+ S_BLST_17, // 86
+ S_BLST_18, // 87
+ S_BLST_19, // 88
+ S_BLST_20, // 89
+ S_BLSF_01, // 90
+ S_BLST_21, // 91
+ S_BLST_22, // 92
+ S_BLST_23, // 93
+ S_BLST_24, // 94
+ S_GREN_00, // 95
+ S_GREN_01, // 96
+ S_GREN_02, // 97
+ S_GREN_03, // 98
+ S_GREN_04, // 99
+ S_GREN_05, // 100
+ S_GREN_06, // 101
+ S_GREN_07, // 102
+ S_GREF_00, // 103
+ S_GREF_01, // 104
+ S_GREF_02, // 105
+ S_GREN_08, // 106
+ S_GREN_09, // 107
+ S_GREN_10, // 108
+ S_GREN_11, // 109
+ S_GREN_12, // 110
+ S_GREN_13, // 111
+ S_GREN_14, // 112
+ S_GREN_15, // 113
+ S_GREF_03, // 114
+ S_GREF_04, // 115
+ S_GREF_05, // 116
+ S_SIGH_00, // 117
+ S_SIGH_01, // 118
+ S_SIGH_02, // 119
+ S_SIGH_03, // 120
+ S_SIGH_04, // 121
+ S_SIGH_05, // 122
+ S_SIGH_06, // 123
+ S_SIGH_07, // 124
+ S_SIGH_08, // 125
+ S_SIGH_09, // 126
+ S_SIGH_10, // 127
+ S_SIGF_00, // 128
+ S_SIGF_01, // 129
+ S_SIGF_02, // 130
+ S_POW1_00, // 131
+ S_POW1_01, // 132
+ S_POW1_02, // 133
+ S_POW1_03, // 134
+ S_POW1_04, // 135
+ S_POW1_05, // 136
+ S_POW1_06, // 137
+ S_POW1_07, // 138
+ S_POW1_08, // 139
+ S_POW1_09, // 140
+ S_POW2_00, // 141
+ S_POW2_01, // 142
+ S_POW2_02, // 143
+ S_POW2_03, // 144
+ S_POW3_00, // 145
+ S_POW3_01, // 146
+ S_POW3_02, // 147
+ S_POW3_03, // 148
+ S_POW3_04, // 149
+ S_POW3_05, // 150
+ S_POW3_06, // 151
+ S_POW3_07, // 152
+ S_ZAP1_00, // 153
+ S_ZAP1_01, // 154
+ S_ZAP1_02, // 155
+ S_ZAP1_03, // 156
+ S_ZAP1_04, // 157
+ S_ZAP1_05, // 158
+ S_ZAP1_06, // 159
+ S_ZAP1_07, // 160
+ S_ZAP1_08, // 161
+ S_ZAP1_09, // 162
+ S_ZAP1_10, // 163
+ S_ZAP1_11, // 164
+ S_SPRY_00, // 165
+ S_SPRY_01, // 166
+ S_SPRY_02, // 167
+ S_SPRY_03, // 168
+ S_SPRY_04, // 169
+ S_SPRY_05, // 170
+ S_SPRY_06, // 171
+ S_BLOD_00, // 172
+ S_BLOD_01, // 173
+ S_BLOD_02, // 174
+ S_PUFY_00, // 175
+ S_PUFY_01, // 176
+ S_PUFY_02, // 177
+ S_PUFY_03, // 178
+ S_SHT1_00, // 179
+ S_SHT1_01, // 180
+ S_SHT2_00, // 181
+ S_SHT2_01, // 182
+ S_GRIN_00, // 183
+ S_GRIN_01, // 184
+ S_GRAP_00, // 185
+ S_GRAP_01, // 186
+ S_UBAM_00, // 187
+ S_UBAM_01, // 188
+ S_BNG2_00, // 189
+ S_BNG2_01, // 190
+ S_BNG2_02, // 191
+ S_BNG2_03, // 192
+ S_BNG2_04, // 193
+ S_BNG2_05, // 194
+ S_BNG2_06, // 195
+ S_BNG2_07, // 196
+ S_BNG2_08, // 197
+ S_BNG4_00, // 198
+ S_BNG4_01, // 199
+ S_BNG4_02, // 200
+ S_BNG4_03, // 201
+ S_BNG4_04, // 202
+ S_BNG4_05, // 203
+ S_BNG4_06, // 204
+ S_BNG4_07, // 205
+ S_BNG4_08, // 206
+ S_BNG4_09, // 207
+ S_BNG4_10, // 208
+ S_BNG4_11, // 209
+ S_BNG4_12, // 210
+ S_BNG4_13, // 211
+ S_BNG3_00, // 212
+ S_BNG3_01, // 213
+ S_BNG3_02, // 214
+ S_BNG3_03, // 215
+ S_BNG3_04, // 216
+ S_BNG3_05, // 217
+ S_BNG3_06, // 218
+ S_BNG3_07, // 219
+ S_BNG3_08, // 220
+ S_BNG3_09, // 221
+ S_BNG3_10, // 222
+ S_FLBE_00, // 223
+ S_FLBE_01, // 224
+ S_FLBE_02, // 225
+ S_FLBE_03, // 226
+ S_FLBE_04, // 227
+ S_FLBE_05, // 228
+ S_FLBE_06, // 229
+ S_FLBE_07, // 230
+ S_FLBE_08, // 231
+ S_FLBE_09, // 232
+ S_FLBE_10, // 233
+ S_XPRK_00, // 234
+ S_OCLW_00, // 235
+ S_CCLW_00, // 236
+ S_TEND_00, // 237
+ S_MICR_00, // 238
+ S_MISS_00, // 239
+ S_MISS_01, // 240
+ S_AROW_00, // 241
+ S_ARWP_00, // 242
+ S_AROW_01, // 243
+ S_TORP_00, // 244
+ S_TORP_01, // 245
+ S_TORP_02, // 246
+ S_TORP_03, // 247
+ S_THIT_00, // 248
+ S_THIT_01, // 249
+ S_THIT_02, // 250
+ S_THIT_03, // 251
+ S_THIT_04, // 252
+ S_TWAV_00, // 253
+ S_TWAV_01, // 254
+ S_TWAV_02, // 255
+ S_MISL_00, // 256
+ S_MISL_01, // 257
+ S_MISL_02, // 258
+ S_MISL_03, // 259
+ S_MISL_04, // 260
+ S_MISL_05, // 261
+ S_MISL_06, // 262
+ S_MISL_07, // 263
+ S_TFOG_00, // 264
+ S_TFOG_01, // 265
+ S_TFOG_02, // 266
+ S_TFOG_03, // 267
+ S_TFOG_04, // 268
+ S_TFOG_05, // 269
+ S_TFOG_06, // 270
+ S_TFOG_07, // 271
+ S_TFOG_08, // 272
+ S_TFOG_09, // 273
+ S_IFOG_00, // 274
+ S_IFOG_01, // 275
+ S_IFOG_02, // 276
+ S_IFOG_03, // 277
+ S_IFOG_04, // 278
+ S_IFOG_05, // 279
+ S_IFOG_06, // 280
+ S_SHRD_00, // 281
+ S_SHRD_01, // 282
+ S_SHRD_02, // 283
+ S_SHRD_03, // 284
+ S_SHRD_04, // 285
+ S_SHRD_05, // 286
+ S_PLAY_00, // 287
+ S_PLAY_01, // 288
+ S_PLAY_02, // 289
+ S_PLAY_03, // 290
+ S_PLAY_04, // 291
+ S_PLAY_05, // 292
+ S_PLAY_06, // 293
+ S_PLAY_07, // 294
+ S_PLAY_08, // 295
+ S_PLAY_09, // 296
+ S_PLAY_10, // 297
+ S_PLAY_11, // 298
+ S_PLAY_12, // 299
+ S_PLAY_13, // 300
+ S_PLAY_14, // 301
+ S_PLAY_15, // 302
+ S_PLAY_16, // 303
+ S_PLAY_17, // 304
+ S_PLAY_18, // 305
+ S_RGIB_00, // 306
+ S_RGIB_01, // 307
+ S_RGIB_02, // 308
+ S_RGIB_03, // 309
+ S_RGIB_04, // 310
+ S_RGIB_05, // 311
+ S_RGIB_06, // 312
+ S_RGIB_07, // 313
+ S_MRYS_00, // 314
+ S_MRNO_00, // 315
+ S_MRNO_01, // 316
+ S_MRNO_02, // 317
+ S_MRNO_03, // 318
+ S_MRNO_04, // 319
+ S_MRST_00, // 320
+ S_MRLK_00, // 321
+ S_MRLK_01, // 322
+ S_MRBD_00, // 323
+ S_MRBD_01, // 324
+ S_MRBD_02, // 325
+ S_MRBD_03, // 326
+ S_MRBD_04, // 327
+ S_MRBD_05, // 328
+ S_MRBD_06, // 329
+ S_MRBD_07, // 330
+ S_MRBD_08, // 331
+ S_MRBD_09, // 332
+ S_MRPN_00, // 333
+ S_MRPN_01, // 334
+ S_MRPN_02, // 335
+ S_MRPN_03, // 336
+ S_MRPN_04, // 337
+ S_MRPN_05, // 338
+ S_MRPN_06, // 339
+ S_MRGT_00, // 340
+ S_MRGT_01, // 341
+ S_MRGT_02, // 342
+ S_MRGT_03, // 343
+ S_MRGT_04, // 344
+ S_MRGT_05, // 345
+ S_MRGT_06, // 346
+ S_MRGT_07, // 347
+ S_MRGT_08, // 348
+ S_BURN_00, // 349
+ S_BURN_01, // 350
+ S_BURN_02, // 351
+ S_BURN_03, // 352
+ S_BURN_04, // 353
+ S_BURN_05, // 354
+ S_BURN_06, // 355
+ S_BURN_07, // 356
+ S_BURN_08, // 357
+ S_BURN_09, // 358
+ S_BURN_10, // 359
+ S_BURN_11, // 360
+ S_BURN_12, // 361
+ S_BURN_13, // 362
+ S_BURN_14, // 363
+ S_BURN_15, // 364
+ S_BURN_16, // 365
+ S_BURN_17, // 366
+ S_BURN_18, // 367
+ S_BURN_19, // 368
+ S_BURN_20, // 369
+ S_BURN_21, // 370
+ S_BURN_22, // 371
+ S_BURN_23, // 372
+ S_DISR_00, // 373
+ S_DISR_01, // 374
+ S_DISR_02, // 375
+ S_DISR_03, // 376
+ S_DISR_04, // 377
+ S_DISR_05, // 378
+ S_DISR_06, // 379
+ S_DISR_07, // 380
+ S_DISR_08, // 381
+ S_DISR_09, // 382
+ S_PEAS_00, // 383
+ S_PEAS_01, // 384
+ S_PEAS_02, // 385
+ S_PEAS_03, // 386
+ S_PEAS_04, // 387
+ S_PEAS_05, // 388
+ S_PEAS_06, // 389
+ S_PEAS_07, // 390
+ S_PEAS_08, // 391
+ S_PEAS_09, // 392
+ S_PEAS_10, // 393
+ S_PEAS_11, // 394
+ S_PEAS_12, // 395
+ S_PEAS_13, // 396
+ S_PEAS_14, // 397
+ S_PEAS_15, // 398
+ S_PEAS_16, // 399
+ S_PEAS_17, // 400
+ S_PEAS_18, // 401
+ S_PEAS_19, // 402
+ S_PEAS_20, // 403
+ S_PEAS_21, // 404
+ S_PEAS_22, // 405
+ S_PEAS_23, // 406
+ S_PEAS_24, // 407
+ S_GIBS_00, // 408
+ S_GIBS_01, // 409
+ S_GIBS_02, // 410
+ S_GIBS_03, // 411
+ S_GIBS_04, // 412
+ S_GIBS_05, // 413
+ S_GIBS_06, // 414
+ S_GIBS_07, // 415
+ S_GIBS_08, // 416
+ S_GIBS_09, // 417
+ S_PEAS_25, // 418
+ S_AGRD_00, // 419
+ S_ARMR_00, // 420
+ S_ARMR_01, // 421
+ S_PLAY_19, // 422
+ S_SACR_00, // 423
+ S_TNK1_00, // 424
+ S_TNK1_01, // 425
+ S_TNK1_02, // 426
+ S_TNK2_00, // 427
+ S_TNK2_01, // 428
+ S_TNK2_02, // 429
+ S_TNK3_00, // 430
+ S_TNK3_01, // 431
+ S_TNK3_02, // 432
+ S_TNK4_00, // 433
+ S_TNK4_01, // 434
+ S_TNK4_02, // 435
+ S_TNK5_00, // 436
+ S_TNK5_01, // 437
+ S_TNK5_02, // 438
+ S_TNK6_00, // 439
+ S_TNK6_01, // 440
+ S_TNK6_02, // 441
+ S_NEAL_00, // 442
+ S_NEAL_01, // 443
+ S_NEAL_02, // 444
+ S_NEAL_03, // 445
+ S_NEAL_04, // 446
+ S_NEAL_05, // 447
+ S_NEAL_06, // 448
+ S_NEAL_07, // 449
+ S_NEAL_08, // 450
+ S_NEAL_09, // 451
+ S_NEAL_10, // 452
+ S_NEAL_11, // 453
+ S_NEAL_12, // 454
+ S_NEAL_13, // 455
+ S_BEGR_00, // 456
+ S_BEGR_01, // 457
+ S_BEGR_02, // 458
+ S_BEGR_03, // 459
+ S_BEGR_04, // 460
+ S_BEGR_05, // 461
+ S_BEGR_06, // 462
+ S_BEGR_07, // 463
+ S_BEGR_08, // 464
+ S_BEGR_09, // 465
+ S_BEGR_10, // 466
+ S_BEGR_11, // 467
+ S_BEGR_12, // 468
+ S_BEGR_13, // 469
+ S_BEGR_14, // 470
+ S_BEGR_15, // 471
+ S_BEGR_16, // 472
+ S_BEGR_17, // 473
+ S_BEGR_18, // 474
+ S_BEGR_19, // 475
+ S_BEGR_20, // 476
+ S_BEGR_21, // 477
+ S_BEGR_22, // 478
+ S_HMN1_00, // 479
+ S_HMN1_01, // 480
+ S_HMN1_02, // 481
+ S_HMN1_03, // 482
+ S_HMN1_04, // 483
+ S_HMN1_05, // 484
+ S_HMN1_06, // 485
+ S_HMN1_07, // 486
+ S_HMN1_08, // 487
+ S_HMN1_09, // 488
+ S_HMN1_10, // 489
+ S_HMN1_11, // 490
+ S_HMN1_12, // 491
+ S_HMN1_13, // 492
+ S_HMN1_14, // 493
+ S_HMN1_15, // 494
+ S_HMN1_16, // 495
+ S_HMN1_17, // 496
+ S_HMN1_18, // 497
+ S_HMN1_19, // 498
+ S_HMN1_20, // 499
+ S_HMN1_21, // 500
+ S_HMN1_22, // 501
+ S_HMN1_23, // 502
+ S_HMN1_24, // 503
+ S_HMN1_25, // 504
+ S_HMN1_26, // 505
+ S_HMN1_27, // 506
+ S_HMN1_28, // 507
+ S_HMN1_29, // 508
+ S_HMN1_30, // 509
+ S_HMN1_31, // 510
+ S_RGIB_08, // 511
+ S_RGIB_09, // 512
+ S_RGIB_10, // 513
+ S_RGIB_11, // 514
+ S_RGIB_12, // 515
+ S_RGIB_13, // 516
+ S_RGIB_14, // 517
+ S_RGIB_15, // 518
+ S_LEDR_00, // 519
+ S_LEDR_01, // 520
+ S_LEDR_02, // 521
+ S_LEAD_00, // 522
+ S_LEAD_01, // 523
+ S_LEAD_02, // 524
+ S_LEAD_03, // 525
+ S_LEAD_04, // 526
+ S_LEAD_05, // 527
+ S_LEAD_06, // 528
+ S_LEAD_07, // 529
+ S_LEAD_08, // 530
+ S_LEAD_09, // 531
+ S_LEAD_10, // 532
+ S_LEAD_11, // 533
+ S_LEAD_12, // 534
+ S_LEAD_13, // 535
+ S_LEAD_14, // 536
+ S_LEAD_15, // 537
+ S_LEAD_16, // 538
+ S_LEAD_17, // 539
+ S_LEAD_18, // 540
+ S_LEAD_19, // 541
+ S_LEAD_20, // 542
+ S_LEAD_21, // 543
+ S_LEAD_22, // 544
+ S_LEAD_23, // 545
+ S_LEAD_24, // 546
+ S_LEAD_25, // 547
+ S_LEAD_26, // 548
+ S_LEAD_27, // 549
+ S_LEAD_28, // 550
+ S_LEAD_29, // 551
+ S_LEAD_30, // 552
+ S_LEAD_31, // 553
+ S_LEAD_32, // 554
+ S_LEAD_33, // 555
+ S_LEAD_34, // 556
+ S_LEAD_35, // 557
+ S_LEAD_36, // 558
+ S_LEAD_37, // 559
+ S_PUFY_04, // 560
+ S_PUFY_05, // 561
+ S_PUFY_06, // 562
+ S_PUFY_07, // 563
+ S_PUFY_08, // 564
+ S_MICR_01, // 565
+ S_MICR_02, // 566
+ S_ROB1_00, // 567
+ S_ROB1_01, // 568
+ S_ROB1_02, // 569
+ S_ROB1_03, // 570
+ S_ROB1_04, // 571
+ S_ROB1_05, // 572
+ S_ROB1_06, // 573
+ S_ROB1_07, // 574
+ S_ROB1_08, // 575
+ S_ROB1_09, // 576
+ S_ROB1_10, // 577
+ S_ROB1_11, // 578
+ S_ROB1_12, // 579
+ S_ROB1_13, // 580
+ S_ROB1_14, // 581
+ S_ROB1_15, // 582
+ S_ROB1_16, // 583
+ S_ROB1_17, // 584
+ S_ROB1_18, // 585
+ S_ROB1_19, // 586
+ S_ROB1_20, // 587
+ S_ROB1_21, // 588
+ S_ROB1_22, // 589
+ S_ROB1_23, // 590
+ S_ROB1_24, // 591
+ S_ROB1_25, // 592
+ S_ROB1_26, // 593
+ S_ROB1_27, // 594
+ S_ROB1_28, // 595
+ S_ROB1_29, // 596
+ S_ROB1_30, // 597
+ S_ROB1_31, // 598
+ S_ROB1_32, // 599
+ S_AGRD_01, // 600
+ S_AGRD_02, // 601
+ S_AGRD_03, // 602
+ S_AGRD_04, // 603
+ S_AGRD_05, // 604
+ S_AGRD_06, // 605
+ S_AGRD_07, // 606
+ S_AGRD_08, // 607
+ S_AGRD_09, // 608
+ S_AGRD_10, // 609
+ S_AGRD_11, // 610
+ S_AGRD_12, // 611
+ S_AGRD_13, // 612
+ S_AGRD_14, // 613
+ S_AGRD_15, // 614
+ S_AGRD_16, // 615
+ S_AGRD_17, // 616
+ S_AGRD_18, // 617
+ S_AGRD_19, // 618
+ S_AGRD_20, // 619
+ S_AGRD_21, // 620
+ S_AGRD_22, // 621
+ S_AGRD_23, // 622
+ S_AGRD_24, // 623
+ S_AGRD_25, // 624
+ S_AGRD_26, // 625
+ S_AGRD_27, // 626
+ S_AGRD_28, // 627
+ S_AGRD_29, // 628
+ S_AGRD_30, // 629
+ S_AGRD_31, // 630
+ S_GIBS_10, // 631
+ S_GIBS_11, // 632
+ S_GIBS_12, // 633
+ S_GIBS_13, // 634
+ S_GIBS_14, // 635
+ S_GIBS_15, // 636
+ S_GIBS_16, // 637
+ S_GIBS_17, // 638
+ S_GIBS_18, // 639
+ S_GIBS_19, // 640
+ S_GIBS_20, // 641
+ S_GIBS_21, // 642
+ S_PGRD_00, // 643
+ S_PGRD_01, // 644
+ S_PGRD_02, // 645
+ S_PGRD_03, // 646
+ S_PGRD_04, // 647
+ S_PGRD_05, // 648
+ S_PGRD_06, // 649
+ S_PGRD_07, // 650
+ S_PGRD_08, // 651
+ S_PGRD_09, // 652
+ S_PGRD_10, // 653
+ S_PGRD_11, // 654
+ S_PGRD_12, // 655
+ S_PGRD_13, // 656
+ S_PGRD_14, // 657
+ S_PGRD_15, // 658
+ S_PGRD_16, // 659
+ S_PGRD_17, // 660
+ S_PGRD_18, // 661
+ S_PGRD_19, // 662
+ S_PGRD_20, // 663
+ S_PGRD_21, // 664
+ S_PGRD_22, // 665
+ S_PGRD_23, // 666
+ S_PGRD_24, // 667
+ S_PGRD_25, // 668
+ S_PGRD_26, // 669
+ S_PGRD_27, // 670
+ S_PGRD_28, // 671
+ S_PGRD_29, // 672
+ S_PGRD_30, // 673
+ S_PGRD_31, // 674
+ S_PGRD_32, // 675
+ S_PGRD_33, // 676
+ S_PGRD_34, // 677
+ S_PGRD_35, // 678
+ S_PGRD_36, // 679
+ S_PGRD_37, // 680
+ S_ROB2_00, // 681
+ S_ROB2_01, // 682
+ S_ROB2_02, // 683
+ S_ROB2_03, // 684
+ S_ROB2_04, // 685
+ S_ROB2_05, // 686
+ S_ROB2_06, // 687
+ S_ROB2_07, // 688
+ S_ROB2_08, // 689
+ S_ROB2_09, // 690
+ S_ROB2_10, // 691
+ S_ROB2_11, // 692
+ S_ROB2_12, // 693
+ S_ROB2_13, // 694
+ S_ROB2_14, // 695
+ S_ROB2_15, // 696
+ S_ROB2_16, // 697
+ S_ROB2_17, // 698
+ S_ROB2_18, // 699
+ S_ROB2_19, // 700
+ S_ROB2_20, // 701
+ S_ROB2_21, // 702
+ S_ROB2_22, // 703
+ S_ROB2_23, // 704
+ S_ROB2_24, // 705
+ S_ROB2_25, // 706
+ S_ROB2_26, // 707
+ S_ROB2_27, // 708
+ S_ROB2_28, // 709
+ S_ROB2_29, // 710
+ S_MLDR_00, // 711
+ S_MLDR_01, // 712
+ S_MLDR_02, // 713
+ S_MLDR_03, // 714
+ S_MLDR_04, // 715
+ S_MLDR_05, // 716
+ S_MLDR_06, // 717
+ S_MLDR_07, // 718
+ S_MLDR_08, // 719
+ S_MLDR_09, // 720
+ S_MLDR_10, // 721
+ S_MLDR_11, // 722
+ S_MLDR_12, // 723
+ S_MLDR_13, // 724
+ S_MLDR_14, // 725
+ S_MLDR_15, // 726
+ S_MLDR_16, // 727
+ S_MLDR_17, // 728
+ S_MLDR_18, // 729
+ S_MLDR_19, // 730
+ S_MLDR_20, // 731
+ S_MLDR_21, // 732
+ S_MLDR_22, // 733
+ S_MLDR_23, // 734
+ S_MLDR_24, // 735
+ S_MLDR_25, // 736
+ S_MLDR_26, // 737
+ S_MLDR_27, // 738
+ S_ORCL_00, // 739
+ S_ORCL_01, // 740
+ S_ORCL_02, // 741
+ S_ORCL_03, // 742
+ S_ORCL_04, // 743
+ S_ORCL_05, // 744
+ S_ORCL_06, // 745
+ S_ORCL_07, // 746
+ S_ORCL_08, // 747
+ S_ORCL_09, // 748
+ S_ORCL_10, // 749
+ S_ORCL_11, // 750
+ S_ORCL_12, // 751
+ S_ORCL_13, // 752
+ S_ORCL_14, // 753
+ S_ORCL_15, // 754
+ S_ORCL_16, // 755
+ S_PRST_00, // 756
+ S_PRST_01, // 757
+ S_PRST_02, // 758
+ S_PRST_03, // 759
+ S_PRST_04, // 760
+ S_PRST_05, // 761
+ S_PRST_06, // 762
+ S_PRST_07, // 763
+ S_PRST_08, // 764
+ S_PRST_09, // 765
+ S_PRST_10, // 766
+ S_PRST_11, // 767
+ S_PRST_12, // 768
+ S_PRST_13, // 769
+ S_PRST_14, // 770
+ S_PRST_15, // 771
+ S_PDED_00, // 772
+ S_PDED_01, // 773
+ S_PDED_02, // 774
+ S_PDED_03, // 775
+ S_PDED_04, // 776
+ S_PDED_05, // 777
+ S_PDED_06, // 778
+ S_PDED_07, // 779
+ S_PDED_08, // 780
+ S_PDED_09, // 781
+ S_PDED_10, // 782
+ S_PDED_11, // 783
+ S_PDED_12, // 784
+ S_PDED_13, // 785
+ S_PDED_14, // 786
+ S_PDED_15, // 787
+ S_PDED_16, // 788
+ S_PDED_17, // 789
+ S_PDED_18, // 790
+ S_PDED_19, // 791
+ S_PDED_20, // 792
+ S_PDED_21, // 793
+ S_PDED_22, // 794
+ S_PDED_23, // 795
+ S_ALN1_00, // 796
+ S_ALN1_01, // 797
+ S_ALN1_02, // 798
+ S_ALN1_03, // 799
+ S_ALN1_04, // 800
+ S_ALN1_05, // 801
+ S_ALN1_06, // 802
+ S_ALN1_07, // 803
+ S_ALN1_08, // 804
+ S_ALN1_09, // 805
+ S_ALN1_10, // 806
+ S_ALN1_11, // 807
+ S_ALN1_12, // 808
+ S_ALN1_13, // 809
+ S_ALN1_14, // 810
+ S_ALN1_15, // 811
+ S_ALN1_16, // 812
+ S_ALN1_17, // 813
+ S_ALN1_18, // 814
+ S_ALN1_19, // 815
+ S_AL1P_00, // 816
+ S_AL1P_01, // 817
+ S_AL1P_02, // 818
+ S_AL1P_03, // 819
+ S_AL1P_04, // 820
+ S_AL1P_05, // 821
+ S_AL1P_06, // 822
+ S_AL1P_07, // 823
+ S_AL1P_08, // 824
+ S_AL1P_09, // 825
+ S_AL1P_10, // 826
+ S_AL1P_11, // 827
+ S_AL1P_12, // 828
+ S_AL1P_13, // 829
+ S_AL1P_14, // 830
+ S_AL1P_15, // 831
+ S_AL1P_16, // 832
+ S_AL1P_17, // 833
+ S_NODE_00, // 834
+ S_NODE_01, // 835
+ S_NODE_02, // 836
+ S_NODE_03, // 837
+ S_NODE_04, // 838
+ S_NODE_05, // 839
+ S_NODE_06, // 840
+ S_MTHD_00, // 841
+ S_MTHD_01, // 842
+ S_MTHD_02, // 843
+ S_MTHD_03, // 844
+ S_MTHD_04, // 845
+ S_MTHD_05, // 846
+ S_MTHD_06, // 847
+ S_MTHD_07, // 848
+ S_MTHD_08, // 849
+ S_MTHD_09, // 850
+ S_MTHD_10, // 851
+ S_ALN1_20, // 852
+ S_ALN1_21, // 853
+ S_ALN1_22, // 854
+ S_ALN1_23, // 855
+ S_ALN1_24, // 856
+ S_ALN1_25, // 857
+ S_ALN1_26, // 858
+ S_ALN1_27, // 859
+ S_ALN1_28, // 860
+ S_ALN1_29, // 861
+ S_ALN1_30, // 862
+ S_ALN1_31, // 863
+ S_ALN1_32, // 864
+ S_ALN1_33, // 865
+ S_ALN1_34, // 866
+ S_ALN1_35, // 867
+ S_ALN1_36, // 868
+ S_ALN1_37, // 869
+ S_ALN1_38, // 870
+ S_ALN1_39, // 871
+ S_ALN1_40, // 872
+ S_ALN1_41, // 873
+ S_ALN1_42, // 874
+ S_ALN1_43, // 875
+ S_ALN1_44, // 876
+ S_ALN1_45, // 877
+ S_ALN1_46, // 878
+ S_ALN1_47, // 879
+ S_ALN1_48, // 880
+ S_ALN1_49, // 881
+ S_ALN1_50, // 882
+ S_ALN1_51, // 883
+ S_ALN1_52, // 884
+ S_ALN1_53, // 885
+ S_ALN1_54, // 886
+ S_ALN1_55, // 887
+ S_ALN1_56, // 888
+ S_ALN1_57, // 889
+ S_MNAM_00, // 890
+ S_MNAM_01, // 891
+ S_MNAM_02, // 892
+ S_MNAM_03, // 893
+ S_MNAM_04, // 894
+ S_MNAM_05, // 895
+ S_MNAM_06, // 896
+ S_MNAM_07, // 897
+ S_MNAM_08, // 898
+ S_MNAM_09, // 899
+ S_MNAM_10, // 900
+ S_MNAM_11, // 901
+ S_MNAL_00, // 902
+ S_MNAL_01, // 903
+ S_MNAL_02, // 904
+ S_MNAL_03, // 905
+ S_MNAL_04, // 906
+ S_MNAL_05, // 907
+ S_MNAL_06, // 908
+ S_MNAL_07, // 909
+ S_MNAL_08, // 910
+ S_MNAL_09, // 911
+ S_MNAL_10, // 912
+ S_MNAL_11, // 913
+ S_MNAL_12, // 914
+ S_MNAL_13, // 915
+ S_MNAL_14, // 916
+ S_MNAL_15, // 917
+ S_MNAL_16, // 918
+ S_MNAL_17, // 919
+ S_MNAL_18, // 920
+ S_MNAL_19, // 921
+ S_MNAL_20, // 922
+ S_MNAL_21, // 923
+ S_MNAL_22, // 924
+ S_MNAL_23, // 925
+ S_MNAL_24, // 926
+ S_MNAL_25, // 927
+ S_MNAL_26, // 928
+ S_MNAL_27, // 929
+ S_MNAL_28, // 930
+ S_MNAL_29, // 931
+ S_MNAL_30, // 932
+ S_MNAL_31, // 933
+ S_MNAL_32, // 934
+ S_MNAL_33, // 935
+ S_MNAL_34, // 936
+ S_MNAL_35, // 937
+ S_MNAL_36, // 938
+ S_MNAL_37, // 939
+ S_MNAL_38, // 940
+ S_MNAL_39, // 941
+ S_MNAL_40, // 942
+ S_MDTH_00, // 943
+ S_MDTH_01, // 944
+ S_MDTH_02, // 945
+ S_MDTH_03, // 946
+ S_MDTH_04, // 947
+ S_MDTH_05, // 948
+ S_MDTH_06, // 949
+ S_MDTH_07, // 950
+ S_MDTH_08, // 951
+ S_MDTH_09, // 952
+ S_MDTH_10, // 953
+ S_MDTH_11, // 954
+ S_MDTH_12, // 955
+ S_MDTH_13, // 956
+ S_MDTH_14, // 957
+ S_NEST_00, // 958
+ S_PODD_00, // 959
+ S_PODD_01, // 960
+ S_PODD_02, // 961
+ S_PODD_03, // 962
+ S_PODD_04, // 963
+ S_PODD_05, // 964
+ S_ZAP6_00, // 965
+ S_ZAP6_01, // 966
+ S_ZAP6_02, // 967
+ S_ZOT3_00, // 968
+ S_ZOT3_01, // 969
+ S_ZOT3_02, // 970
+ S_ZOT3_03, // 971
+ S_ZOT3_04, // 972
+ S_ZAP6_03, // 973
+ S_ZAP6_04, // 974
+ S_ZAP6_05, // 975
+ S_ZAP7_00, // 976
+ S_ZAP7_01, // 977
+ S_ZAP7_02, // 978
+ S_ZAP7_03, // 979
+ S_ZAP7_04, // 980
+ S_ZOT1_00, // 981
+ S_ZOT1_01, // 982
+ S_ZOT1_02, // 983
+ S_ZOT1_03, // 984
+ S_ZOT1_04, // 985
+ S_ZAP5_00, // 986
+ S_ZAP5_01, // 987
+ S_ZAP5_02, // 988
+ S_ZAP5_03, // 989
+ S_ZOT2_00, // 990
+ S_ZOT2_01, // 991
+ S_ZOT2_02, // 992
+ S_ZOT2_03, // 993
+ S_ZOT2_04, // 994
+ S_SEWR_00, // 995
+ S_SEWR_01, // 996
+ S_SEWR_02, // 997
+ S_SEWR_03, // 998
+ S_SEWR_04, // 999
+ S_SEWR_05, // 1000
+ S_SEWR_06, // 1001
+ S_SEWR_07, // 1002
+ S_SEWR_08, // 1003
+ S_SEWR_09, // 1004
+ S_SEWR_10, // 1005
+ S_SEWR_11, // 1006
+ S_SEWR_12, // 1007
+ S_SEWR_13, // 1008
+ S_SPID_00, // 1009
+ S_SPID_01, // 1010
+ S_SPID_02, // 1011
+ S_SPID_03, // 1012
+ S_SPID_04, // 1013
+ S_SPID_05, // 1014
+ S_SPID_06, // 1015
+ S_SPID_07, // 1016
+ S_SPID_08, // 1017
+ S_SPID_09, // 1018
+ S_SPID_10, // 1019
+ S_SPID_11, // 1020
+ S_SPID_12, // 1021
+ S_SPID_13, // 1022
+ S_SPID_14, // 1023
+ S_SPID_15, // 1024
+ S_SPID_16, // 1025
+ S_SPID_17, // 1026
+ S_SPID_18, // 1027
+ S_SPID_19, // 1028
+ S_SPID_20, // 1029
+ S_SPID_21, // 1030
+ S_SPID_22, // 1031
+ S_SPID_23, // 1032
+ S_SPID_24, // 1033
+ S_SPID_25, // 1034
+ S_SPID_26, // 1035
+ S_SPID_27, // 1036
+ S_SPID_28, // 1037
+ S_SPID_29, // 1038
+ S_SPID_30, // 1039
+ S_SPID_31, // 1040
+ S_SPID_32, // 1041
+ S_SPID_33, // 1042
+ S_SPID_34, // 1043
+ S_SPID_35, // 1044
+ S_SPID_36, // 1045
+ S_SPID_37, // 1046
+ S_ROB3_00, // 1047
+ S_ROB3_01, // 1048
+ S_ROB3_02, // 1049
+ S_ROB3_03, // 1050
+ S_ROB3_04, // 1051
+ S_ROB3_05, // 1052
+ S_ROB3_06, // 1053
+ S_ROB3_07, // 1054
+ S_ROB3_08, // 1055
+ S_ROB3_09, // 1056
+ S_ROB3_10, // 1057
+ S_ROB3_11, // 1058
+ S_ROB3_12, // 1059
+ S_ROB3_13, // 1060
+ S_ROB3_14, // 1061
+ S_ROB3_15, // 1062
+ S_ROB3_16, // 1063
+ S_ROB3_17, // 1064
+ S_ROB3_18, // 1065
+ S_ROB3_19, // 1066
+ S_ROB3_20, // 1067
+ S_ROB3_21, // 1068
+ S_ROB3_22, // 1069
+ S_ROB3_23, // 1070
+ S_ROB3_24, // 1071
+ S_ROB3_25, // 1072
+ S_ROB3_26, // 1073
+ S_ROB3_27, // 1074
+ S_ROB3_28, // 1075
+ S_ROB3_29, // 1076
+ S_ROB3_30, // 1077
+ S_ROB3_31, // 1078
+ S_ROB3_32, // 1079
+ S_ROB3_33, // 1080
+ S_ROB3_34, // 1081
+ S_ROB3_35, // 1082
+ S_ROB3_36, // 1083
+ S_ROB3_37, // 1084
+ S_RBB3_00, // 1085
+ S_RBB3_01, // 1086
+ S_RBB3_02, // 1087
+ S_RBB3_03, // 1088
+ S_RBB3_04, // 1089
+ S_RBB3_05, // 1090
+ S_RBB3_06, // 1091
+ S_RBB3_07, // 1092
+ S_PRGR_00, // 1093
+ S_PRGR_01, // 1094
+ S_PRGR_02, // 1095
+ S_PRGR_03, // 1096
+ S_PRGR_04, // 1097
+ S_PRGR_05, // 1098
+ S_PRGR_06, // 1099
+ S_PRGR_07, // 1100
+ S_PRGR_08, // 1101
+ S_PRGR_09, // 1102
+ S_PRGR_10, // 1103
+ S_PRGR_11, // 1104
+ S_PRGR_12, // 1105
+ S_PRGR_13, // 1106
+ S_PRGR_14, // 1107
+ S_PRGR_15, // 1108
+ S_PRGR_16, // 1109
+ S_PRGR_17, // 1110
+ S_PRGR_18, // 1111
+ S_PRGR_19, // 1112
+ S_PRGR_20, // 1113
+ S_PRGR_21, // 1114
+ S_PRGR_22, // 1115
+ S_PRGR_23, // 1116
+ S_PRGR_24, // 1117
+ S_PRGR_25, // 1118
+ S_PRGR_26, // 1119
+ S_PRGR_27, // 1120
+ S_PRGR_28, // 1121
+ S_PRGR_29, // 1122
+ S_PRGR_30, // 1123
+ S_PRGR_31, // 1124
+ S_PRGR_32, // 1125
+ S_PRGR_33, // 1126
+ S_BASE_00, // 1127
+ S_BASE_01, // 1128
+ S_BASE_02, // 1129
+ S_BASE_03, // 1130
+ S_BASE_04, // 1131
+ S_BASE_05, // 1132
+ S_BASE_06, // 1133
+ S_BASE_07, // 1134
+ S_FRBL_00, // 1135
+ S_FRBL_01, // 1136
+ S_FRBL_02, // 1137
+ S_FRBL_03, // 1138
+ S_FRBL_04, // 1139
+ S_FRBL_05, // 1140
+ S_FRBL_06, // 1141
+ S_FRBL_07, // 1142
+ S_FRBL_08, // 1143
+ S_KLAX_00, // 1144
+ S_KLAX_01, // 1145
+ S_KLAX_02, // 1146
+ S_TURT_00, // 1147
+ S_TURT_01, // 1148
+ S_TURT_02, // 1149
+ S_TURT_03, // 1150
+ S_TURT_04, // 1151
+ S_BALL_00, // 1152
+ S_BALL_01, // 1153
+ S_BALL_02, // 1154
+ S_BALL_03, // 1155
+ S_BALL_04, // 1156
+ S_TURT_05, // 1157
+ S_PSTN_00, // 1158
+ S_PSTN_01, // 1159
+ S_PSTN_02, // 1160
+ S_PSTN_03, // 1161
+ S_PSTN_04, // 1162
+ S_PSTN_05, // 1163
+ S_PSTN_06, // 1164
+ S_PSTN_07, // 1165
+ S_PSTN_08, // 1166
+ S_PSTN_09, // 1167
+ S_PSTN_10, // 1168
+ S_SECR_00, // 1169
+ S_SECR_01, // 1170
+ S_SECR_02, // 1171
+ S_SECR_03, // 1172
+ S_SECR_04, // 1173
+ S_SECR_05, // 1174
+ S_SECR_06, // 1175
+ S_SECR_07, // 1176
+ S_SECR_08, // 1177
+ S_SECR_09, // 1178
+ S_SECR_10, // 1179
+ S_SECR_11, // 1180
+ S_SECR_12, // 1181
+ S_SECR_13, // 1182
+ S_SECR_14, // 1183
+ S_SECR_15, // 1184
+ S_XPRK_01, // 1185
+ S_XPRK_02, // 1186
+ S_TARG_00, // 1187
+ S_RING_00, // 1188
+ S_EARS_00, // 1189
+ S_COMM_00, // 1190
+ S_BOOM_00, // 1191
+ S_BOOM_01, // 1192
+ S_BOOM_02, // 1193
+ S_BOOM_03, // 1194
+ S_BOOM_04, // 1195
+ S_BOOM_05, // 1196
+ S_BOOM_06, // 1197
+ S_BOOM_07, // 1198
+ S_BOOM_08, // 1199
+ S_BOOM_09, // 1200
+ S_BOOM_10, // 1201
+ S_BOOM_11, // 1202
+ S_BOOM_12, // 1203
+ S_BOOM_13, // 1204
+ S_BOOM_14, // 1205
+ S_BOOM_15, // 1206
+ S_BOOM_16, // 1207
+ S_BOOM_17, // 1208
+ S_BOOM_18, // 1209
+ S_BOOM_19, // 1210
+ S_BOOM_20, // 1211
+ S_BOOM_21, // 1212
+ S_BOOM_22, // 1213
+ S_BOOM_23, // 1214
+ S_BOOM_24, // 1215
+ S_RATT_00, // 1216
+ S_RATT_01, // 1217
+ S_RATT_02, // 1218
+ S_RATT_03, // 1219
+ S_RATT_04, // 1220
+ S_RATT_05, // 1221
+ S_RATT_06, // 1222
+ S_HOGN_00, // 1223
+ S_HOGN_01, // 1224
+ S_HOGN_02, // 1225
+ S_DEAD_00, // 1226
+ S_SBAN_00, // 1227
+ S_BOTR_00, // 1228
+ S_HATR_00, // 1229
+ S_TOPR_00, // 1230
+ S_COUP_00, // 1231
+ S_COUP_01, // 1232
+ S_COUP_02, // 1233
+ S_BUBB_00, // 1234
+ S_BUBF_00, // 1235
+ S_BUBC_00, // 1236
+ S_ASPR_00, // 1237
+ S_SPDL_00, // 1238
+ S_SPDL_01, // 1239
+ S_SPDL_02, // 1240
+ S_TOKN_00, // 1241
+ S_OTOK_00, // 1242
+ S_HELT_00, // 1243
+ S_GUNT_00, // 1244
+ S_FULL_00, // 1245
+ S_FULL_01, // 1246
+ S_MEAT_00, // 1247
+ S_MEAT_01, // 1248
+ S_MEAT_02, // 1249
+ S_MEAT_03, // 1250
+ S_MEAT_04, // 1251
+ S_MEAT_05, // 1252
+ S_MEAT_06, // 1253
+ S_MEAT_07, // 1254
+ S_MEAT_08, // 1255
+ S_MEAT_09, // 1256
+ S_MEAT_10, // 1257
+ S_MEAT_11, // 1258
+ S_MEAT_12, // 1259
+ S_MEAT_13, // 1260
+ S_MEAT_14, // 1261
+ S_MEAT_15, // 1262
+ S_MEAT_16, // 1263
+ S_MEAT_17, // 1264
+ S_MEAT_18, // 1265
+ S_MEAT_19, // 1266
+ S_JUNK_00, // 1267
+ S_JUNK_01, // 1268
+ S_JUNK_02, // 1269
+ S_JUNK_03, // 1270
+ S_JUNK_04, // 1271
+ S_JUNK_05, // 1272
+ S_JUNK_06, // 1273
+ S_JUNK_07, // 1274
+ S_JUNK_08, // 1275
+ S_JUNK_09, // 1276
+ S_JUNK_10, // 1277
+ S_JUNK_11, // 1278
+ S_JUNK_12, // 1279
+ S_JUNK_13, // 1280
+ S_JUNK_14, // 1281
+ S_JUNK_15, // 1282
+ S_JUNK_16, // 1283
+ S_JUNK_17, // 1284
+ S_JUNK_18, // 1285
+ S_JUNK_19, // 1286
+ S_FFOT_00, // 1287
+ S_FFOT_01, // 1288
+ S_FFOT_02, // 1289
+ S_FFOT_03, // 1290
+ S_DIE1_00, // 1291
+ S_BEAC_00, // 1292
+ S_BEAC_01, // 1293
+ S_BEAC_02, // 1294
+ S_ARM1_00, // 1295
+ S_ARM2_00, // 1296
+ S_BARW_00, // 1297
+ S_BARW_01, // 1298
+ S_BARW_02, // 1299
+ S_BARW_03, // 1300
+ S_BARW_04, // 1301
+ S_BARW_05, // 1302
+ S_BARW_06, // 1303
+ S_BARW_07, // 1304
+ S_BART_00, // 1305
+ S_BART_01, // 1306
+ S_BART_02, // 1307
+ S_BART_03, // 1308
+ S_BART_04, // 1309
+ S_BART_05, // 1310
+ S_BART_06, // 1311
+ S_BART_07, // 1312
+ S_BART_08, // 1313
+ S_BART_09, // 1314
+ S_BART_10, // 1315
+ S_BART_11, // 1316
+ S_LAMP_00, // 1317
+ S_LANT_00, // 1318
+ S_BARL_00, // 1319
+ S_BARL_01, // 1320
+ S_BARL_02, // 1321
+ S_BARL_03, // 1322
+ S_BOWL_00, // 1323
+ S_BOWL_01, // 1324
+ S_BOWL_02, // 1325
+ S_BOWL_03, // 1326
+ S_BRAZ_00, // 1327
+ S_BRAZ_01, // 1328
+ S_BRAZ_02, // 1329
+ S_BRAZ_03, // 1330
+ S_TRCH_00, // 1331
+ S_TRCH_01, // 1332
+ S_TRCH_02, // 1333
+ S_TRCH_03, // 1334
+ S_LTRH_00, // 1335
+ S_LTRH_01, // 1336
+ S_LTRH_02, // 1337
+ S_LTRH_03, // 1338
+ S_LMPC_00, // 1339
+ S_LMPC_01, // 1340
+ S_LMPC_02, // 1341
+ S_LMPC_03, // 1342
+ S_LOGS_00, // 1343
+ S_LOGS_01, // 1344
+ S_LOGS_02, // 1345
+ S_LOGS_03, // 1346
+ S_TRHO_00, // 1347
+ S_WATR_00, // 1348
+ S_MUGG_00, // 1349
+ S_FUSL_00, // 1350
+ S_CRD1_00, // 1351
+ S_CRD2_00, // 1352
+ S_TPAS_00, // 1353
+ S_KY1G_00, // 1354
+ S_KY2S_00, // 1355
+ S_KY3B_00, // 1356
+ S_HAND_00, // 1357
+ S_CRYS_00, // 1358
+ S_CRYS_01, // 1359
+ S_CRYS_02, // 1360
+ S_CRYS_03, // 1361
+ S_CRYS_04, // 1362
+ S_CRYS_05, // 1363
+ S_PRIS_00, // 1364
+ S_PWR1_00, // 1365
+ S_PWR2_00, // 1366
+ S_PWR3_00, // 1367
+ S_ORAC_00, // 1368
+ S_GYID_00, // 1369
+ S_FUBR_00, // 1370
+ S_WARE_00, // 1371
+ S_RCRY_00, // 1372
+ S_BCRY_00, // 1373
+ S_CHAP_00, // 1374
+ S_TUNL_00, // 1375
+ S_BLTK_00, // 1376
+ S_SECK_00, // 1377
+ S_MINE_00, // 1378
+ S_REBL_00, // 1379
+ S_PROC_00, // 1380
+ S_ANKH_00, // 1381
+ S_GOID_00, // 1382
+ S_STMP_00, // 1383
+ S_MDKT_00, // 1384
+ S_COIN_00, // 1385
+ S_CRED_00, // 1386
+ S_SACK_00, // 1387
+ S_CHST_00, // 1388
+ S_SHD1_00, // 1389
+ S_SHD1_01, // 1390
+ S_SHD1_02, // 1391
+ S_SHD1_03, // 1392
+ S_MASK_00, // 1393
+ S_UNIF_00, // 1394
+ S_OFIC_00, // 1395
+ S_PMAP_00, // 1396
+ S_PMAP_01, // 1397
+ S_PMUP_00, // 1398
+ S_PMUP_01, // 1399
+ S_BLIT_00, // 1400
+ S_BBOX_00, // 1401
+ S_MSSL_00, // 1402
+ S_ROKT_00, // 1403
+ S_BRY1_00, // 1404
+ S_BRY1_01, // 1405
+ S_CPAC_00, // 1406
+ S_CPAC_01, // 1407
+ S_PQRL_00, // 1408
+ S_XQRL_00, // 1409
+ S_GRN1_00, // 1410
+ S_GRN2_00, // 1411
+ S_BKPK_00, // 1412
+ S_RELC_00, // 1413
+ S_RIFL_00, // 1414
+ S_RIFL_01, // 1415
+ S_FLAM_00, // 1416
+ S_BFLM_00, // 1417
+ S_MMSL_00, // 1418
+ S_TRPD_00, // 1419
+ S_GRND_00, // 1420
+ S_CBOW_00, // 1421
+ S_SIGL_00, // 1422
+ S_SIGL_01, // 1423
+ S_SIGL_02, // 1424
+ S_SIGL_03, // 1425
+ S_SIGL_04, // 1426
+ S_LITE_00, // 1427
+ S_CNDL_00, // 1428
+ S_CLBR_00, // 1429
+ S_LITS_00, // 1430
+ S_LITB_00, // 1431
+ S_LITG_00, // 1432
+ S_ROK1_00, // 1433
+ S_ROK2_00, // 1434
+ S_ROK3_00, // 1435
+ S_ROK4_00, // 1436
+ S_LOGG_00, // 1437
+ S_LOGG_01, // 1438
+ S_LOGG_02, // 1439
+ S_LOGG_03, // 1440
+ S_RUB1_00, // 1441
+ S_RUB2_00, // 1442
+ S_RUB3_00, // 1443
+ S_RUB4_00, // 1444
+ S_RUB5_00, // 1445
+ S_RUB6_00, // 1446
+ S_RUB7_00, // 1447
+ S_RUB8_00, // 1448
+ S_CHAN_00, // 1449
+ S_STAT_00, // 1450
+ S_DSTA_00, // 1451
+ S_CRAB_00, // 1452
+ S_CAGE_00, // 1453
+ S_TREE_00, // 1454
+ S_TREE_01, // 1455
+ S_TREE_02, // 1456
+ S_TRE1_00, // 1457
+ S_BUSH_00, // 1458
+ S_SHRB_00, // 1459
+ S_STAK_00, // 1460
+ S_BAR1_00, // 1461
+ S_VASE_00, // 1462
+ S_VASE_01, // 1463
+ S_STOL_00, // 1464
+ S_POT1_00, // 1465
+ S_TUB1_00, // 1466
+ S_ANVL_00, // 1467
+ S_TLMP_00, // 1468
+ S_TLMP_01, // 1469
+ S_TRAY_00, // 1470
+ S_APOW_00, // 1471
+ S_AFED_00, // 1472
+ S_DRIP_00, // 1473
+ S_DRIP_01, // 1474
+ S_DRIP_02, // 1475
+ S_DRIP_03, // 1476
+ S_DRIP_04, // 1477
+ S_DRIP_05, // 1478
+ S_DRIP_06, // 1479
+ S_DRIP_07, // 1480
+ S_CDRP_00, // 1481
+ S_CDRP_01, // 1482
+ S_CDRP_02, // 1483
+ S_CDRP_03, // 1484
+ S_SPLH_00, // 1485
+ S_SPLH_01, // 1486
+ S_SPLH_02, // 1487
+ S_SPLH_03, // 1488
+ S_SPLH_04, // 1489
+ S_SPLH_05, // 1490
+ S_SPLH_06, // 1491
+ S_SPLH_07, // 1492
+ S_WTFT_00, // 1493
+ S_WTFT_01, // 1494
+ S_WTFT_02, // 1495
+ S_WTFT_03, // 1496
+ S_HERT_00, // 1497
+ S_HERT_01, // 1498
+ S_HERT_02, // 1499
+ S_TELP_00, // 1500
+ S_TELP_01, // 1501
+ S_TELP_02, // 1502
+ S_TELP_03, // 1503
+ S_MONI_00, // 1504
+ S_STEL_00, // 1505
+ S_STLA_00, // 1506
+ S_STLE_00, // 1507
+ S_HUGE_00, // 1508
+ S_HUGE_01, // 1509
+ S_HUGE_02, // 1510
+ S_HUGE_03, // 1511
+ S_STLG_00, // 1512
+ S_STLG_01, // 1513
+ S_STLG_02, // 1514
+ S_STLG_03, // 1515
+ S_STLG_04, // 1516
+ S_STLG_05, // 1517
+ NUMSTATES
+
+} statenum_t;
+
+
+typedef struct
+{
+ spritenum_t sprite;
+ int frame;
+ int tics;
+ // void (*action) ();
+ actionf_t action;
+ statenum_t nextstate;
+ //int misc1; // villsa [STRIFE] unused
+ //int misc2; // villsa [STRIFE] unused
+} state_t;
+
+extern state_t states[NUMSTATES];
+extern char *sprnames[];
+
+typedef enum
+{
+ MT_FIELDGUARD, //000
+ MT_PLAYER, //001
+ MT_SHOPKEEPER_W, //002
+ MT_SHOPKEEPER_B, //003
+ MT_SHOPKEEPER_A, //004
+ MT_SHOPKEEPER_M, //005
+ MT_PEASANT2_A, //006
+ MT_PEASANT2_B, //007
+ MT_PEASANT2_C, //008
+ MT_PEASANT5_A, //009
+ MT_PEASANT5_B, //010
+ MT_PEASANT5_C, //011
+ MT_PEASANT4_A, //012
+ MT_PEASANT4_B, //013
+ MT_PEASANT4_C, //014
+ MT_PEASANT6_A, //015
+ MT_PEASANT6_B, //016
+ MT_PEASANT6_C, //017
+ MT_PEASANT3_A, //018
+ MT_PEASANT3_B, //019
+ MT_PEASANT3_C, //020
+ MT_PEASANT8_A, //021
+ MT_PEASANT8_B, //022
+ MT_PEASANT8_C, //023
+ MT_PEASANT7_A, //024
+ MT_PEASANT7_B, //025
+ MT_PEASANT7_C, //026
+ MT_PEASANT1, //027
+ MT_ZOMBIE, //028
+ MT_BECOMING, //029
+ MT_ZOMBIESPAWNER, //030
+ MT_HUGE_TANK_1, //031
+ MT_HUGE_TANK_2, //032
+ MT_HUGE_TANK_3, //033
+ MT_TANK_4, //034
+ MT_TANK_5, //035
+ MT_TANK_6, //036
+ MT_KNEELING_GUY, //037
+ MT_BEGGAR1, //038
+ MT_BEGGAR2, //039
+ MT_BEGGAR3, //040
+ MT_BEGGAR4, //041
+ MT_BEGGAR5, //042
+ MT_REBEL1, //043
+ MT_REBEL2, //044
+ MT_REBEL3, //045
+ MT_REBEL4, //046
+ MT_REBEL5, //047
+ MT_REBEL6, //048
+ MT_RLEADER, //049
+ MT_RLEADER2, //050
+ MT_MISSILESMOKE, //051
+ MT_REAVER, //052
+ MT_GUARD1, //053
+ MT_GUARD2, //054
+ MT_GUARD3, //055
+ MT_GUARD4, //056
+ MT_GUARD5, //057
+ MT_GUARD6, //058
+ MT_GUARD7, //059
+ MT_GUARD8, //060
+ MT_SHADOWGUARD, //061
+ MT_PGUARD, //062
+ MT_CRUSADER, //063
+ MT_BISHOP, //064
+ MT_ORACLE, //065
+ MT_PRIEST, //066
+ MT_SPECTRE_A, //067
+ MT_NODE, //068
+ MT_SPECTREHEAD, //069
+ MT_SPECTRE_B, //070
+ MT_SPECTRE_C, //071
+ MT_SPECTRE_D, //072
+ MT_SPECTRE_E, //073
+ MT_ENTITY, //074
+ MT_SUBENTITY, //075
+ MT_NEST, //076
+ MT_POD, //077
+ MT_SIGIL_B_SHOT, //078
+ MT_SIGIL_SB_SHOT, //079
+ MT_SIGIL_C_SHOT, //080
+ MT_SIGIL_SC_SHOT, //081
+ MT_SIGIL_E_OFFSHOOT, //082
+ MT_SIGIL_TRAIL, //083
+ MT_SIGIL_E_SHOT, //084
+ MT_SIGIL_SE_SHOT, //085
+ MT_SIGIL_A_ZAP_LEFT, //086
+ MT_SIGIL_A_ZAP_RIGHT, //087
+ MT_SIGIL_A_GROUND, //088
+ MT_SIGIL_D_SHOT, //089
+ MT_SIGIL_SD_SHOT, //090
+ MT_SENTINEL, //091
+ MT_STALKER, //092
+ MT_INQUISITOR, //093
+ MT_INQARM, //094
+ MT_PROGRAMMER, //095
+ MT_PROGRAMMERBASE, //096
+ MT_HOOKSHOT, //097
+ MT_CHAINSHOT, //098
+ MT_MINIMISSLE, //099
+ MT_C_MISSILE, //100
+ MT_SEEKMISSILE, //101
+ MT_ELECARROW, //102
+ MT_POISARROW, //103
+ MT_R_LASER, //104
+ MT_L_LASER, //105
+ MT_HEGRENADE, //106
+ MT_PGRENADE, //107
+ MT_INQGRENADE, //108
+ MT_PFLAME, //109
+ MT_TORPEDO, //110
+ MT_TORPEDOSPREAD, //111
+ MT_SFIREBALL, //112
+ MT_C_FLAME, //113
+ MT_STRIFEPUFF3, //114
+ MT_STRIFEPUFF, //115
+ MT_SPARKPUFF, //116
+ MT_BLOOD_DEATH, //117
+ MT_TFOG, //118
+ MT_IFOG, //119
+ MT_TELEPORTMAN, //120
+ MT_MISC_01, //121
+ MT_TURRET, //122
+ MT_GATE, //123
+ MT_COMPUTER, //124
+ MT_INV_MED1, //125
+ MT_INV_MED2, //126
+ MT_INV_MED3, //127
+ MT_DEGNINORE, //128
+ MT_INV_ARMOR2, //129
+ MT_INV_ARMOR1, //130
+ MT_MISC_22, //131
+ MT_MISC_11, //132
+ MT_KEY_BASE, //133
+ MT_GOVSKEY, //134
+ MT_KEY_TRAVEL, //135
+ MT_KEY_ID_BLUE, //136
+ MT_PRISONKEY, //137
+ MT_KEY_HAND, //138
+ MT_POWER1KEY, //139
+ MT_POWER2KEY, //140
+ MT_POWER3KEY, //141
+ MT_KEY_GOLD, //142
+ MT_KEY_ID_GOLD, //143
+ MT_KEY_SILVER, //144
+ MT_KEY_ORACLE, //145
+ MT_MILITARYID, //146
+ MT_KEY_ORDER, //147
+ MT_KEY_WAREHOUSE, //148
+ MT_KEY_BRASS, //149
+ MT_KEY_RED_CRYSTAL, //150
+ MT_KEY_BLUE_CRYSTAL, //151
+ MT_KEY_CHAPEL, //152
+ MT_CATACOMBKEY, //153
+ MT_SECURITYKEY, //154
+ MT_KEY_CORE, //155
+ MT_KEY_MAULER, //156
+ MT_KEY_FACTORY, //157
+ MT_KEY_MINE, //158
+ MT_NEWKEY5, //159
+ MT_INV_SHADOWARMOR, //160
+ MT_INV_SUIT, //161
+ MT_QUEST_UNIFORM, //162
+ MT_QUEST_GUARD_UNIFORM, //163
+ MT_INV_SUPERMAP, //164
+ MT_INV_RADAR, //165
+ MT_BEACON, //166
+ MT_INV_TARGETER, //167
+ MT_MONY_1, //168
+ MT_MONY_10, //169
+ MT_MONY_25, //170
+ MT_MONY_50, //171
+ MT_MONY_300, //172
+ MT_TOKEN_RING, //173
+ MT_INV_CHALICE, //174
+ MT_TOKEN_EAR, //175
+ MT_INV_COMMUNICATOR, //176
+ MT_AGREN, //177
+ MT_APGREN, //178
+ MT_ACLIP, //179
+ MT_AAMMOBOX, //180
+ MT_AMINI, //181
+ MT_AMINIBOX, //182
+ MT_ACELL, //183
+ MT_APCELL, //184
+ MT_APAROW, //185
+ MT_AAROW, //186
+ MT_INV_SATCHEL, //187
+ MT_PULSE, //188
+ MT_RIFLESTAND, //189
+ MT_FLAMETHROWER, //190
+ MT_TOKEN_FLAME_THROWER_PARTS, //191
+ MT_MISSILELAUNCHER, //192
+ MT_BLASTER, //193
+ MT_CROSSBOW, //194
+ MT_GRENADELAUNCHER, //195
+ MT_SIGIL_A, //196
+ MT_SIGIL_B, //197
+ MT_SIGIL_C, //198
+ MT_SIGIL_D, //199
+ MT_SIGIL_E, //200
+ MT_POWER_CRYSTAL, //201
+ MT_RAT, //202
+ MT_MISC_05, //203
+ MT_MISC_06, //204
+ MT_MISC_15, //205
+ MT_LIGHT14, //206
+ MT_LIGHT13, //207
+ MT_LIGHT12, //208
+ MT_LIGHT18, //209
+ MT_PILLAR2, //210
+ MT_PILLAR3, //211
+ MT_PILLAR4, //212
+ MT_PILLAR5, //213
+ MT_PILLAR6, //214
+ MT_PILLAR7, //215
+ MT_CAVE2, //216
+ MT_CAVE3, //217
+ MT_CAVE4, //218
+ MT_CAVE6, //219
+ MT_CAVE7, //220
+ MT_CAVE5, //221
+ MT_LIGHT2, //222
+ MT_LIGHT3, //223
+ MT_MISC_03, //224
+ MT_MISC_13, //225
+ MT_MISC_02, //226
+ MT_MISC_07, //227
+ MT_BIO2, //228
+ MT_TELEPORTSTAND, //229
+ MT_DEADTHING1, //230
+ MT_DEADTHING2, //231
+ MT_DEADTHING3, //232
+ MT_DEADTHING4, //233
+ MT_DEADTHING5, //234
+ MT_DEADTHING6, //235
+ MT_BIO1, //236
+ MT_GIBS, //237
+ MT_MISC_04, //238
+ MT_LIGHT11, //239
+ MT_LIGHT10, //240
+ MT_LIGHT9, //241
+ MT_LIGHT8, //242
+ MT_MISC_14, //243
+ MT_LIGHT1, //244
+ MT_PILLAR8, //245
+ MT_PILLAR9, //246
+ MT_LIGHT15, //247
+ MT_LIGHT4, //248
+ MT_LIGHT5, //249
+ MT_ROCK1, //250
+ MT_ROCK2, //251
+ MT_ROCK3, //252
+ MT_ROCK4, //253
+ MT_TREE7, //254
+ MT_RUBBLE1, //255
+ MT_RUBBLE2, //256
+ MT_RUBBLE3, //257
+ MT_RUBBLE4, //258
+ MT_RUBBLE5, //259
+ MT_RUBBLE6, //260
+ MT_RUBBLE7, //261
+ MT_RUBBLE8, //262
+ MT_MISC_08, //263
+ MT_LIGHT6, //264
+ MT_LIGHT7, //265
+ MT_TREE2, //266
+ MT_TREE3, //267
+ MT_TREE4, //268
+ MT_TREE1, //269
+ MT_TREE6, //270
+ MT_TREE5, //271
+ MT_CAVE1, //272
+ MT_PILLAR1, //273
+ MT_MISC_10, //274
+ MT_MISC_09, //275
+ MT_MISC_17, //276
+ MT_MISC_18, //277
+ MT_MISC_19, //278
+ MT_MISC_20, //279
+ MT_LIGHT16, //280
+ MT_LIGHT17, //281
+ MT_MISC_21, //282
+ MT_MISC_12, //283
+ MT_MISC_26, //284
+ MT_MISC_23, //285
+ MT_MISC_24, //286
+ MT_MISC_25, //287
+ MT_COUPLING, //288
+ MT_COUPLING_BROKEN, //289
+ MT_PILLAR10, //290
+ MT_PILLAR11, //291
+ MT_PILLAR12, //292
+ MT_PILLAR13, //293
+ MT_LIGHT19, //294
+ MT_MEAT, //295
+ MT_JUNK, //296
+ MT_BURNDROP, //297
+ MT_TOKEN_AMMO, //298
+ MT_TOKEN_HEALTH, //299
+ MT_TOKEN, //300
+ MT_TOKEN_ALARM, //301
+ MT_TOKEN_DOOR1, //302
+ MT_TOKEN_SHOPCLOSE, //303
+ MT_TOKEN_PRISON_PASS, //304
+ MT_TOKEN_DOOR3, //305
+ MT_TOKEN_STAMINA, //306
+ MT_TOKEN_NEW_ACCURACY, //307
+ MT_TOKEN_REPORT, //308
+ MT_TOKEN_TOUGHNESS, //309
+ MT_TOKEN_ACCURACY, //310
+ MT_TOKEN_ORACLE_PASS, //311
+ MT_TOKEN_QUEST1, //312
+ MT_TOKEN_QUEST2, //313
+ MT_TOKEN_QUEST3, //314
+ MT_TOKEN_QUEST4, //315
+ MT_TOKEN_QUEST5, //316
+ MT_TOKEN_QUEST6, //317
+ MT_TOKEN_QUEST7, //318
+ MT_TOKEN_QUEST8, //319
+ MT_TOKEN_QUEST9, //320
+ MT_TOKEN_QUEST10, //321
+ MT_TOKEN_QUEST11, //322
+ MT_TOKEN_QUEST12, //323
+ MT_TOKEN_QUEST13, //324
+ MT_TOKEN_CRYSTAL, //325
+ MT_TOKEN_QUEST15, //326
+ MT_GATEQUEST, //327
+ MT_TOKEN_QUEST17, //328
+ MT_TOKEN_QUEST18, //329
+ MT_TOKEN_QUEST19, //330
+ MT_TOKEN_QUEST20, //331
+ MT_TOKEN_BISHOP, //332
+ MT_TOKEN_QUEST22, //333
+ MT_TOKEN_ORACLE, //334
+ MT_TOKEN_MACIL, //335
+ MT_TOKEN_QUEST25, //336
+ MT_TOKEN_LOREMASTER, //337
+ MT_SECRQUEST, //338
+ MT_TOKEN_QUEST28, //339
+ MT_TOKEN_QUEST29, //340
+ MT_TOKEN_QUEST30, //341
+ MT_TOKEN_QUEST31, //342
+ MT_SLIDESHOW, //343
+ NUMMOBJTYPES
+
+} mobjtype_t;
+
+// villsa [STRIFE] updated mobjinfo struct
+typedef struct
+{
+ int doomednum;
+ int spawnstate;
+ int spawnhealth;
+ int seestate;
+ int seesound;
+ int reactiontime;
+ int attacksound;
+ int painstate;
+ int painchance;
+ int painsound;
+ int meleestate;
+ int missilestate;
+ int crashstate;
+ int deathstate;
+ int xdeathstate;
+ int deathsound;
+ int speed;
+ int radius;
+ int height;
+ int mass;
+ int damage;
+ int activesound;
+ int flags;
+ char* name;
+} mobjinfo_t;
+
+extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
+
+#endif
diff --git a/src/strife/m_menu.c b/src/strife/m_menu.c
new file mode 100644
index 00000000..a4d1b0a7
--- /dev/null
+++ b/src/strife/m_menu.c
@@ -0,0 +1,2377 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 selection menu, options, episode etc.
+// Sliders and icons. Kinda widget stuff.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdlib.h>
+#include <ctype.h>
+
+
+#include "doomdef.h"
+#include "doomkeys.h"
+#include "dstrings.h"
+
+#include "d_main.h"
+#include "deh_main.h"
+
+#include "i_swap.h"
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+#include "z_zone.h"
+#include "v_video.h"
+#include "w_wad.h"
+
+#include "r_local.h"
+
+
+#include "hu_stuff.h"
+
+#include "g_game.h"
+
+#include "m_argv.h"
+#include "m_controls.h"
+#include "m_saves.h" // [STRIFE]
+#include "p_saveg.h"
+
+#include "s_sound.h"
+
+#include "doomstat.h"
+
+// Data.
+#include "sounds.h"
+
+#include "m_menu.h"
+#include "p_dialog.h"
+
+
+extern void M_QuitStrife(int);
+
+extern patch_t* hu_font[HU_FONTSIZE];
+extern boolean message_dontfuckwithme;
+
+extern boolean chat_on; // in heads-up code
+extern boolean sendsave; // [STRIFE]
+
+//
+// defaulted values
+//
+int mouseSensitivity = 5;
+
+// [STRIFE]: removed this entirely
+// Show messages has default, 0 = off, 1 = on
+//int showMessages = 1;
+
+
+// Blocky mode, has default, 0 = high, 1 = normal
+int detailLevel = 0;
+int screenblocks = 9;
+
+// 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);
+
+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;
+boolean menupause; // haleyjd 08/29/10: [STRIFE] New global
+int menupausetime; // haleyjd 09/04/10: [STRIFE] New global
+boolean menuindialog; // haleyjd 09/04/10: ditto
+
+// haleyjd 08/27/10: [STRIFE] SKULLXOFF == -28, LINEHEIGHT == 19
+#define CURSORXOFF -28
+#define LINEHEIGHT 19
+
+extern boolean sendpause;
+char savegamestrings[10][SAVESTRINGSIZE];
+
+char endstring[160];
+
+// haleyjd 09/04/10: [STRIFE] Moved menuitem / menu structures into header
+// because they are needed externally by the dialog engine.
+
+// haleyjd 08/27/10: [STRIFE] skull* stuff changed to cursor* stuff
+short itemOn; // menu item skull is on
+short cursorAnimCounter; // skull animation counter
+short whichCursor; // which skull to draw
+
+// graphic name of cursors
+// haleyjd 08/27/10: [STRIFE] M_SKULL* -> M_CURS*
+char *cursorName[8] = {"M_CURS1", "M_CURS2", "M_CURS3", "M_CURS4",
+ "M_CURS5", "M_CURS6", "M_CURS7", "M_CURS8" };
+
+// haleyjd 20110210 [STRIFE]: skill level for menus
+int menuskill;
+
+// current menudef
+menu_t* currentMenu;
+
+// haleyjd 03/01/13: [STRIFE] v1.31-only:
+// Keeps track of whether the save game menu is being used to name a new
+// character slot, or to just save the current game. In the v1.31 disassembly
+// this was the new dword_8632C variable.
+boolean namingCharacter;
+
+//
+// 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_ReadThis3(int choice); // [STRIFE]
+
+//void M_ChangeMessages(int choice); [STRIFE]
+void M_ChangeSensitivity(int choice);
+void M_SfxVol(int choice);
+void M_VoiceVol(int choice); // [STRIFE]
+void M_MusicVol(int choice);
+void M_SizeDisplay(int choice);
+void M_StartGame(int choice);
+void M_Sound(int choice);
+
+//void M_FinishReadThis(int choice); - [STRIFE] unused
+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_DrawReadThis3(void); // [STRIFE]
+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);
+int M_StringWidth(char *string);
+int M_StringHeight(char *string);
+void M_StartMessage(char *string,void *routine,boolean input);
+void M_StopMessage(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,'h'}, // haleyjd 08/28/10: 'r' -> 'h'
+ {1,"M_QUITG",M_QuitStrife,'q'}
+};
+
+menu_t MainDef =
+{
+ main_end,
+ NULL,
+ MainMenu,
+ M_DrawMainMenu,
+ 97,45, // haleyjd 08/28/10: [STRIFE] changed y coord
+ 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[]=
+{
+ // haleyjd 08/28/10: [STRIFE] changed all shortcut letters
+ {1,"M_JKILL", M_ChooseSkill, 't'},
+ {1,"M_ROUGH", M_ChooseSkill, 'r'},
+ {1,"M_HURT", M_ChooseSkill, 'v'},
+ {1,"M_ULTRA", M_ChooseSkill, 'e'},
+ {1,"M_NMARE", M_ChooseSkill, 'b'}
+};
+
+menu_t NewDef =
+{
+ newg_end, // # of menu items
+ &MainDef, // previous menu - haleyjd [STRIFE] changed to MainDef
+ NewGameMenu, // menuitem_t ->
+ M_DrawNewGame, // drawing routine ->
+ 48,63, // x,y
+ toorough // lastOn - haleyjd [STRIFE]: default to skill 1
+};
+
+//
+// OPTIONS MENU
+//
+enum
+{
+ // haleyjd 08/28/10: [STRIFE] Removed messages, mouse sens., detail.
+ endgame,
+ scrnsize,
+ option_empty1,
+ soundvol,
+ opt_end
+} options_e;
+
+menuitem_t OptionsMenu[]=
+{
+ // haleyjd 08/28/10: [STRIFE] Removed messages, mouse sens., detail.
+ {1,"M_ENDGAM", M_EndGame,'e'},
+ {2,"M_SCRNSZ", M_SizeDisplay,'s'},
+ {-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 & [STRIFE] 3
+//
+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_ReadThis3,0} // haleyjd 08/28/10: [STRIFE] Go to ReadThis3
+};
+
+menu_t ReadDef2 =
+{
+ read2_end,
+ &ReadDef1,
+ ReadMenu2,
+ M_DrawReadThis2,
+ 250,185, // haleyjd 08/28/10: [STRIFE] changed coords
+ 0
+};
+
+// haleyjd 08/28/10: Added Read This! menu 3
+enum
+{
+ rdthsempty3,
+ read3_end
+} read_e3;
+
+menuitem_t ReadMenu3[]=
+{
+ {1,"",M_ClearMenus,0}
+};
+
+menu_t ReadDef3 =
+{
+ read3_end,
+ &ReadDef2,
+ ReadMenu3,
+ M_DrawReadThis3,
+ 250, 185,
+ 0
+};
+
+//
+// SOUND VOLUME MENU
+//
+enum
+{
+ sfx_vol,
+ sfx_empty1,
+ music_vol,
+ sfx_empty2,
+ voice_vol,
+ sfx_empty3,
+ sfx_mouse,
+ sfx_empty4,
+ sound_end
+} sound_e;
+
+// haleyjd 08/29/10:
+// [STRIFE]
+// * Added voice volume
+// * Moved mouse sensitivity here (who knows why...)
+menuitem_t SoundMenu[]=
+{
+ {2,"M_SFXVOL",M_SfxVol,'s'},
+ {-1,"",0,'\0'},
+ {2,"M_MUSVOL",M_MusicVol,'m'},
+ {-1,"",0,'\0'},
+ {2,"M_VOIVOL",M_VoiceVol,'v'},
+ {-1,"",0,'\0'},
+ {2,"M_MSENS",M_ChangeSensitivity,'m'},
+ {-1,"",0,'\0'}
+};
+
+menu_t SoundDef =
+{
+ sound_end,
+ &OptionsDef,
+ SoundMenu,
+ M_DrawSound,
+ 80,35, // [STRIFE] changed y coord 64 -> 35
+ 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
+};
+
+void M_DrawNameChar(void);
+
+//
+// NAME CHARACTER MENU
+//
+// [STRIFE]
+// haleyjd 20110210: New "Name Your Character" Menu
+//
+menu_t NameCharDef =
+{
+ load_end,
+ &NewDef,
+ SaveMenu,
+ M_DrawNameChar,
+ 80,54,
+ 0
+};
+
+
+//
+// M_ReadSaveStrings
+// read the strings from the savegame files
+//
+// [STRIFE]
+// haleyjd 20110210: Rewritten to read "name" file in each slot directory
+//
+void M_ReadSaveStrings(void)
+{
+ FILE *handle;
+ int i;
+ char *fname = NULL;
+
+ for(i = 0; i < load_end; i++)
+ {
+ if(fname)
+ Z_Free(fname);
+ fname = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(i, "\\name"));
+
+ handle = fopen(fname, "rb");
+ if(handle == NULL)
+ {
+ strcpy(savegamestrings[i], EMPTYSTRING);
+ LoadMenu[i].status = 0;
+ continue;
+ }
+ fread(savegamestrings[i], 1, SAVESTRINGSIZE, handle);
+ fclose(handle);
+ LoadMenu[i].status = 1;
+ }
+
+ if(fname)
+ Z_Free(fname);
+}
+
+//
+// M_DrawNameChar
+//
+// haleyjd 09/22/10: [STRIFE] New function
+// Handler for drawing the "Name Your Character" menu.
+//
+void M_DrawNameChar(void)
+{
+ int i;
+
+ M_WriteText(72, 28, DEH_String("Name Your Character"));
+
+ 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[quickSaveSlot]);
+ M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*quickSaveSlot,"_");
+ }
+}
+
+//
+// M_DoNameChar
+//
+// haleyjd 09/22/10: [STRIFE] New function
+// Handler for items in the "Name Your Character" menu.
+//
+void M_DoNameChar(int choice)
+{
+ int map;
+
+ // 20130301: clear naming character flag for 1.31 save logic
+ if(gameversion == exe_strife_1_31)
+ namingCharacter = false;
+ sendsave = 1;
+ ClearTmp();
+ G_WriteSaveName(choice, savegamestrings[choice]);
+ quickSaveSlot = choice;
+ SaveDef.lastOn = choice;
+ ClearSlot();
+ FromCurr();
+
+ if(isdemoversion)
+ map = 33;
+ else
+ map = 2;
+
+ G_DeferedInitNew(menuskill, map);
+ M_ClearMenus(0);
+}
+
+//
+// M_LoadGame & Cie.
+//
+void M_DrawLoad(void)
+{
+ int i;
+
+ V_DrawPatchDirect(72, 28,
+ W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE));
+
+ 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_DrawPatchDirect(x - 8, y + 7,
+ W_CacheLumpName(DEH_String("M_LSLEFT"), PU_CACHE));
+
+ for (i = 0;i < 24;i++)
+ {
+ V_DrawPatchDirect(x, y + 7,
+ W_CacheLumpName(DEH_String("M_LSCNTR"), PU_CACHE));
+ x += 8;
+ }
+
+ V_DrawPatchDirect(x, y + 7,
+ W_CacheLumpName(DEH_String("M_LSRGHT"), PU_CACHE));
+}
+
+
+
+//
+// User wants to load this game
+//
+void M_LoadSelect(int choice)
+{
+ // [STRIFE]: completely rewritten
+ char *name = NULL;
+
+ G_WriteSaveName(choice, savegamestrings[choice]);
+ ToCurr();
+
+ // use safe & portable filepath concatenation for Choco
+ name = M_SafeFilePath(savegamedir, M_MakeStrifeSaveDir(choice, ""));
+
+ G_ReadCurrent(name);
+ quickSaveSlot = choice;
+ M_ClearMenus(0);
+
+ Z_Free(name);
+}
+
+//
+// Selected from DOOM menu
+//
+// [STRIFE] Verified unmodified
+//
+void M_LoadGame (int choice)
+{
+ if (netgame)
+ {
+ M_StartMessage(DEH_String(LOADNET), NULL, false);
+ return;
+ }
+
+ M_SetupNextMenu(&LoadDef);
+ M_ReadSaveStrings();
+}
+
+
+//
+// M_SaveGame & Cie.
+//
+void M_DrawSave(void)
+{
+ int i;
+
+ V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE));
+ 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[quickSaveSlot]);
+ M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*quickSaveSlot,"_");
+ }
+}
+
+//
+// M_Responder calls this when user is finished
+//
+void M_DoSave(int slot)
+{
+ // [STRIFE]: completely rewritten
+ if(slot >= 0)
+ {
+ sendsave = 1;
+ G_WriteSaveName(slot, savegamestrings[slot]);
+ M_ClearMenus(0);
+ quickSaveSlot = slot;
+ FromCurr();
+ }
+ else
+ M_StartMessage(DEH_String(QSAVESPOT), NULL, false);
+}
+
+//
+// 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;
+
+ // [STRIFE]
+ quickSaveSlot = choice;
+ //saveSlot = 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)
+{
+ // [STRIFE]
+ if (netgame)
+ {
+ // haleyjd 20110211: Hooray for Rogue's awesome multiplayer support...
+ M_StartMessage(DEH_String("You can't save a netgame"), NULL, false);
+ return;
+ }
+ if (!usergame)
+ {
+ M_StartMessage(DEH_String(SAVEDEAD),NULL,false);
+ return;
+ }
+
+ if (gamestate != GS_LEVEL)
+ return;
+
+ // [STRIFE]
+ if(gameversion == exe_strife_1_31)
+ {
+ // haleyjd 20130301: in 1.31, we can choose a slot again.
+ M_SetupNextMenu(&SaveDef);
+ M_ReadSaveStrings();
+ }
+ else
+ {
+ // In 1.2 and lower, you save over your character slot exclusively
+ M_ReadSaveStrings();
+ M_DoSave(quickSaveSlot);
+ }
+}
+
+
+
+//
+// M_QuickSave
+//
+char tempstring[80];
+
+void M_QuickSaveResponse(int key)
+{
+ if (key == key_menu_confirm)
+ {
+ M_DoSave(quickSaveSlot);
+ S_StartSound(NULL, sfx_mtalht); // [STRIFE] sound
+ }
+}
+
+void M_QuickSave(void)
+{
+ if (netgame)
+ {
+ // haleyjd 20110211 [STRIFE]: More fun...
+ M_StartMessage(DEH_String("You can't save a netgame"), NULL, false);
+ return;
+ }
+
+ 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;
+ }
+ DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]);
+ M_StartMessage(tempstring,M_QuickSaveResponse,true);
+}
+
+
+
+//
+// M_QuickLoadResponse
+//
+void M_QuickLoadResponse(int key)
+{
+ if (key == key_menu_confirm)
+ {
+ M_LoadSelect(quickSaveSlot);
+ S_StartSound(NULL, sfx_mtalht); // [STRIFE] sound
+ }
+}
+
+//
+// M_QuickLoad
+//
+// [STRIFE] Verified unmodified
+//
+void M_QuickLoad(void)
+{
+ if (netgame)
+ {
+ M_StartMessage(DEH_String(QLOADNET),NULL,false);
+ return;
+ }
+
+ if (quickSaveSlot < 0)
+ {
+ M_StartMessage(DEH_String(QSAVESPOT),NULL,false);
+ return;
+ }
+ DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]);
+ M_StartMessage(tempstring,M_QuickLoadResponse,true);
+}
+
+
+
+
+//
+// Read This Menus
+// Had a "quick hack to fix romero bug"
+// haleyjd 08/28/10: [STRIFE] Draw HELP1, unconditionally.
+//
+void M_DrawReadThis1(void)
+{
+ inhelpscreens = true;
+
+ V_DrawPatchDirect (0, 0, W_CacheLumpName(DEH_String("HELP1"), PU_CACHE));
+}
+
+
+
+//
+// Read This Menus
+// haleyjd 08/28/10: [STRIFE] Not optional, draws HELP2
+//
+void M_DrawReadThis2(void)
+{
+ inhelpscreens = true;
+
+ V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP2"), PU_CACHE));
+}
+
+
+//
+// Read This Menus
+// haleyjd 08/28/10: [STRIFE] New function to draw HELP3.
+//
+void M_DrawReadThis3(void)
+{
+ inhelpscreens = true;
+
+ V_DrawPatchDirect(0, 0, W_CacheLumpName(DEH_String("HELP3"), PU_CACHE));
+}
+
+//
+// Change Sfx & Music volumes
+//
+// haleyjd 08/29/10: [STRIFE]
+// * Changed title graphic coordinates
+// * Added voice volume and sensitivity sliders
+//
+void M_DrawSound(void)
+{
+ V_DrawPatchDirect (100, 10, W_CacheLumpName(DEH_String("M_SVOL"), PU_CACHE));
+
+ M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_vol+1),
+ 16,sfxVolume);
+
+ M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(music_vol+1),
+ 16,musicVolume);
+
+ M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(voice_vol+1),
+ 16,voiceVolume);
+
+ M_DrawThermo(SoundDef.x,SoundDef.y+LINEHEIGHT*(sfx_mouse+1),
+ 16,mouseSensitivity);
+}
+
+void M_Sound(int choice)
+{
+ M_SetupNextMenu(&SoundDef);
+}
+
+void M_SfxVol(int choice)
+{
+ switch(choice)
+ {
+ case 0:
+ if (sfxVolume)
+ sfxVolume--;
+ break;
+ case 1:
+ if (sfxVolume < 15)
+ sfxVolume++;
+ break;
+ }
+
+ S_SetSfxVolume(sfxVolume * 8);
+}
+
+//
+// M_VoiceVol
+//
+// haleyjd 08/29/10: [STRIFE] New function
+// Sets voice volume level.
+//
+void M_VoiceVol(int choice)
+{
+ switch(choice)
+ {
+ case 0:
+ if (voiceVolume)
+ voiceVolume--;
+ break;
+ case 1:
+ if (voiceVolume < 15)
+ voiceVolume++;
+ break;
+ }
+
+ S_SetVoiceVolume(voiceVolume * 8);
+}
+
+void M_MusicVol(int choice)
+{
+ switch(choice)
+ {
+ case 0:
+ if (musicVolume)
+ musicVolume--;
+ break;
+ case 1:
+ if (musicVolume < 15)
+ musicVolume++;
+ break;
+ }
+
+ S_SetMusicVolume(musicVolume * 8);
+}
+
+
+
+
+//
+// M_DrawMainMenu
+//
+// haleyjd 08/27/10: [STRIFE] Changed x coordinate; M_DOOM -> M_STRIFE
+//
+void M_DrawMainMenu(void)
+{
+ V_DrawPatchDirect(84, 2,
+ W_CacheLumpName(DEH_String("M_STRIFE"), PU_CACHE));
+}
+
+
+
+
+//
+// M_NewGame
+//
+// haleyjd 08/31/10: [STRIFE] Changed M_NEWG -> M_NGAME
+//
+void M_DrawNewGame(void)
+{
+ V_DrawPatchDirect(96, 14, W_CacheLumpName(DEH_String("M_NGAME"), PU_CACHE));
+ V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_SKILL"), PU_CACHE));
+}
+
+void M_NewGame(int choice)
+{
+ if (netgame && !demoplayback)
+ {
+ M_StartMessage(DEH_String(NEWGAME),NULL,false);
+ return;
+ }
+ // haleyjd 09/07/10: [STRIFE] Removed Chex Quest and DOOM gamemodes
+ if(gameversion == exe_strife_1_31)
+ namingCharacter = true; // for 1.31 save logic
+ M_SetupNextMenu(&NewDef);
+}
+
+
+//
+// M_Episode
+//
+
+// haleyjd: [STRIFE] Unused
+/*
+int epi;
+
+void M_DrawEpisode(void)
+{
+ V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_EPISOD"), PU_CACHE));
+}
+
+void M_VerifyNightmare(int key)
+{
+ if (key != key_menu_confirm)
+ return;
+
+ G_DeferedInitNew(nightmare, 1);
+ M_ClearMenus (0);
+}
+*/
+
+void M_ChooseSkill(int choice)
+{
+ // haleyjd 09/07/10: Removed nightmare confirmation
+ // [STRIFE]: start "Name Your Character" menu
+ menuskill = choice;
+ currentMenu = &NameCharDef;
+ itemOn = NameCharDef.lastOn;
+ M_ReadSaveStrings();
+}
+
+/*
+// haleyjd [STRIFE] Unused
+void M_Episode(int choice)
+{
+ if ( (gamemode == shareware)
+ && choice)
+ {
+ M_StartMessage(DEH_String(SWSTRING),NULL,false);
+ M_SetupNextMenu(&ReadDef1);
+ return;
+ }
+
+ // Yet another hack...
+ if ( (gamemode == registered)
+ && (choice > 2))
+ {
+ 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)
+{
+ // haleyjd 08/27/10: [STRIFE] M_OPTTTL -> M_OPTION
+ V_DrawPatchDirect(108, 15,
+ W_CacheLumpName(DEH_String("M_OPTION"), PU_CACHE));
+
+ // haleyjd 08/26/10: [STRIFE] Removed messages, sensitivity, detail.
+
+ M_DrawThermo(OptionsDef.x,OptionsDef.y+LINEHEIGHT*(scrnsize+1),
+ 9,screenSize);
+}
+
+void M_Options(int choice)
+{
+ M_SetupNextMenu(&OptionsDef);
+}
+
+//
+// M_AutoUseHealth
+//
+// [STRIFE] New function
+// haleyjd 20110211: toggle autouse health state
+//
+void M_AutoUseHealth(void)
+{
+ if(!netgame && usergame)
+ {
+ players[consoleplayer].cheats ^= CF_AUTOHEALTH;
+
+ if(players[consoleplayer].cheats & CF_AUTOHEALTH)
+ players[consoleplayer].message = DEH_String("Auto use health ON");
+ else
+ players[consoleplayer].message = DEH_String("Auto use health OFF");
+ }
+}
+
+//
+// M_ChangeShowText
+//
+// [STRIFE] New function
+//
+void M_ChangeShowText(void)
+{
+ dialogshowtext ^= true;
+
+ if(dialogshowtext)
+ players[consoleplayer].message = DEH_String("Conversation Text On");
+ else
+ players[consoleplayer].message = DEH_String("Conversation Text Off");
+}
+
+//
+// Toggle messages on/off
+//
+// [STRIFE] Messages cannot be disabled in Strife
+/*
+void M_ChangeMessages(int choice)
+{
+ // warning: unused parameter `int choice'
+ choice = 0;
+ showMessages = 1 - showMessages;
+
+ if (!showMessages)
+ players[consoleplayer].message = DEH_String(MSGOFF);
+ else
+ players[consoleplayer].message = DEH_String(MSGON);
+
+ message_dontfuckwithme = true;
+}
+*/
+
+
+//
+// M_EndGame
+//
+void M_EndGameResponse(int key)
+{
+ if (key != key_menu_confirm)
+ return;
+
+ currentMenu->lastOn = itemOn;
+ M_ClearMenus (0);
+ D_StartTitle ();
+}
+
+void M_EndGame(int choice)
+{
+ choice = 0;
+ if (!usergame)
+ {
+ S_StartSound(NULL,sfx_oof);
+ return;
+ }
+
+ if (netgame)
+ {
+ M_StartMessage(DEH_String(NETEND),NULL,false);
+ return;
+ }
+
+ M_StartMessage(DEH_String(ENDGAME),M_EndGameResponse,true);
+}
+
+
+
+
+//
+// M_ReadThis
+//
+void M_ReadThis(int choice)
+{
+ choice = 0;
+ M_SetupNextMenu(&ReadDef1);
+}
+
+//
+// M_ReadThis2
+//
+// haleyjd 08/28/10: [STRIFE] Eliminated DOOM stuff.
+//
+void M_ReadThis2(int choice)
+{
+ choice = 0;
+ M_SetupNextMenu(&ReadDef2);
+}
+
+//
+// M_ReadThis3
+//
+// haleyjd 08/28/10: [STRIFE] New function.
+//
+void M_ReadThis3(int choice)
+{
+ choice = 0;
+ M_SetupNextMenu(&ReadDef3);
+}
+
+/*
+// haleyjd 08/28/10: [STRIFE] Not used.
+void M_FinishReadThis(int choice)
+{
+ choice = 0;
+ M_SetupNextMenu(&MainDef);
+}
+*/
+
+#if 0
+extern void F_StartCast(void);
+
+//
+// M_CheckStartCast
+//
+// [STRIFE] New but unused function. Was going to start a cast
+// call from within the menu system... not functional even in
+// the earliest demo version.
+//
+void M_CheckStartCast()
+{
+ if(usergame)
+ {
+ M_StartMessage(DEH_String("You have to end your game first."), NULL, false);
+ return;
+ }
+
+ F_StartCast();
+ M_ClearMenus(0);
+}
+#endif
+
+//
+// M_QuitResponse
+//
+// haleyjd 09/11/10: [STRIFE] Modifications to start up endgame
+// demosequence.
+//
+void M_QuitResponse(int key)
+{
+ char buffer[20];
+
+ if (key != key_menu_confirm)
+ return;
+
+ if(netgame)
+ I_Quit();
+ else
+ {
+ DEH_snprintf(buffer, sizeof(buffer), "qfmrm%i", gametic % 8 + 1);
+ I_StartVoice(buffer);
+ D_QuitGame();
+ }
+}
+
+/*
+// haleyjd 09/11/10: [STRIFE] Unused
+static char *M_SelectEndMessage(void)
+{
+}
+*/
+
+//
+// M_QuitStrife
+//
+// [STRIFE] Renamed from M_QuitDOOM
+// haleyjd 09/11/10: No randomized text message; that's taken care of
+// by the randomized voice message after confirmation.
+//
+void M_QuitStrife(int choice)
+{
+ DEH_snprintf(endstring, sizeof(endstring),
+ "Do you really want to leave?\n\n" DOSY);
+
+ M_StartMessage(endstring, M_QuitResponse, true);
+}
+
+
+
+
+void M_ChangeSensitivity(int choice)
+{
+ switch(choice)
+ {
+ case 0:
+ if (mouseSensitivity)
+ mouseSensitivity--;
+ break;
+ case 1:
+ if (mouseSensitivity < 9)
+ mouseSensitivity++;
+ break;
+ }
+}
+
+/*
+// haleyjd [STRIFE] Unused
+void M_ChangeDetail(int choice)
+{
+ choice = 0;
+ detailLevel = 1 - detailLevel;
+
+ R_SetViewSize (screenblocks, detailLevel);
+
+ if (!detailLevel)
+ players[consoleplayer].message = DEH_String(DETAILHI);
+ else
+ players[consoleplayer].message = DEH_String(DETAILLO);
+}
+*/
+
+// [STRIFE] Verified unmodified
+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, detailLevel);
+}
+
+
+
+
+//
+// Menu Functions
+//
+
+//
+// M_DrawThermo
+//
+// haleyjd 08/28/10: [STRIFE] Changes to some patch coordinates.
+//
+void
+M_DrawThermo
+( int x,
+ int y,
+ int thermWidth,
+ int thermDot )
+{
+ int xx;
+ int yy; // [STRIFE] Needs a temp y coordinate variable
+ int i;
+
+ xx = x;
+ yy = y + 6; // [STRIFE] +6 to y coordinate
+ V_DrawPatchDirect(xx, yy, W_CacheLumpName(DEH_String("M_THERML"), PU_CACHE));
+ xx += 8;
+ for (i=0;i<thermWidth;i++)
+ {
+ V_DrawPatchDirect(xx, yy, W_CacheLumpName(DEH_String("M_THERMM"), PU_CACHE));
+ xx += 8;
+ }
+ V_DrawPatchDirect(xx, yy, W_CacheLumpName(DEH_String("M_THERMR"), PU_CACHE));
+
+ // [STRIFE] +2 to initial y coordinate
+ V_DrawPatchDirect((x + 8) + thermDot * 8, y + 2,
+ W_CacheLumpName(DEH_String("M_THERMO"), PU_CACHE));
+}
+
+
+// haleyjd: These are from DOOM v0.5 and the prebeta! They drew those ugly red &
+// blue checkboxes... preserved for historical interest, as not in Strife.
+void
+M_DrawEmptyCell
+( menu_t* menu,
+ int item )
+{
+ V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1,
+ W_CacheLumpName(DEH_String("M_CELL1"), PU_CACHE));
+}
+
+void
+M_DrawSelCell
+( menu_t* menu,
+ int item )
+{
+ V_DrawPatchDirect(menu->x - 10, menu->y + item * LINEHEIGHT - 1,
+ W_CacheLumpName(DEH_String("M_CELL2"), PU_CACHE));
+}
+
+
+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(char* string)
+{
+ size_t i;
+ int w = 0;
+ int c;
+
+ for (i = 0;i < strlen(string);i++)
+ {
+ c = toupper(string[i]) - HU_FONTSTART;
+ if (c < 0 || c >= HU_FONTSIZE)
+ w += 4;
+ else
+ w += SHORT (hu_font[c]->width);
+ }
+
+ return w;
+}
+
+
+
+//
+// Find string height from hu_font chars
+//
+int M_StringHeight(char* string)
+{
+ size_t i;
+ int h;
+ int height = SHORT(hu_font[0]->height);
+
+ h = height;
+ for (i = 0;i < strlen(string);i++)
+ if (string[i] == '\n')
+ h += height;
+
+ return h;
+}
+
+
+//
+// M_WriteText
+//
+// Write a string using the hu_font
+// haleyjd 09/04/10: [STRIFE]
+// * Rogue made a lot of changes to this for the dialog system.
+//
+int
+M_WriteText
+( int x,
+ int y,
+ const char* string) // haleyjd: made const for safety w/dialog engine
+{
+ int w;
+ const char* ch;
+ int c;
+ int cx;
+ int cy;
+
+ ch = string;
+ cx = x;
+ cy = y;
+
+ while(1)
+ {
+ c = *ch++;
+ if (!c)
+ break;
+
+ // haleyjd 09/04/10: [STRIFE] Don't draw spaces at the start of lines.
+ if(c == ' ' && cx == x)
+ continue;
+
+ if (c == '\n')
+ {
+ cx = x;
+ cy += 11; // haleyjd 09/04/10: [STRIFE]: Changed 12 -> 11
+ continue;
+ }
+
+ c = toupper(c) - HU_FONTSTART;
+ if (c < 0 || c>= HU_FONTSIZE)
+ {
+ cx += 4;
+ continue;
+ }
+
+ w = SHORT (hu_font[c]->width);
+
+ // haleyjd 09/04/10: [STRIFE] Different linebreak handling
+ if (cx + w > SCREENWIDTH - 20)
+ {
+ cx = x;
+ cy += 11;
+ --ch;
+ }
+ else
+ {
+ V_DrawPatchDirect(cx, cy, hu_font[c]);
+ cx += w;
+ }
+ }
+
+ // [STRIFE] Return final y coordinate.
+ return cy + 12;
+}
+
+//
+// M_DialogDimMsg
+//
+// [STRIFE] New function
+// haleyjd 09/04/10: Painstakingly transformed from the assembly code, as the
+// decompiler could not touch it. Redimensions a string to fit on screen, leaving
+// at least a 20 pixel margin on the right side. The string passed in must be
+// writable.
+//
+void M_DialogDimMsg(int x, int y, char *str, boolean useyfont)
+{
+ int rightbound = (SCREENWIDTH - 20) - x;
+ patch_t **fontarray; // ebp
+ int linewidth = 0; // esi
+ int i = 0; // edx
+ char *message = str; // edi
+ char bl; // bl
+
+ if(useyfont)
+ fontarray = yfont;
+ else
+ fontarray = hu_font;
+
+ bl = toupper(*message);
+
+ if(!bl)
+ return;
+
+ // outer loop - run to end of string
+ do
+ {
+ if(bl != '\n')
+ {
+ int charwidth; // eax
+ int tempwidth; // ecx
+
+ if(bl < HU_FONTSTART || bl > HU_FONTEND)
+ charwidth = 4;
+ else
+ charwidth = SHORT(fontarray[bl - HU_FONTSTART]->width);
+
+ tempwidth = linewidth + charwidth;
+
+ // Test if the line still fits within the boundary...
+ if(tempwidth >= rightbound)
+ {
+ // Doesn't fit...
+ char *tempptr = &message[i]; // ebx
+ char al; // al
+
+ // inner loop - run backward til a space (or the start of the
+ // string) is found, subtracting width off the current line.
+ // BUG: shouldn't we stop at a previous '\n' too?
+ while(*tempptr != ' ' && i > 0)
+ {
+ tempptr--;
+ // BUG: they didn't add the first char to linewidth yet...
+ linewidth -= charwidth;
+ i--;
+ al = toupper(*tempptr);
+ if(al < HU_FONTSTART || al > HU_FONTEND)
+ charwidth = 4;
+ else
+ charwidth = SHORT(fontarray[al - HU_FONTSTART]->width);
+ }
+ // Replace the space with a linebreak.
+ // BUG: what if i is zero? ... infinite loop time!
+ message[i] = '\n';
+ linewidth = 0;
+ }
+ else
+ {
+ // The line does fit.
+ // Spaces at the start of a line don't count though.
+ if(!(bl == ' ' && linewidth == 0))
+ linewidth += charwidth;
+ }
+ }
+ else
+ linewidth = 0; // '\n' seen, so reset the line width
+ }
+ while((bl = toupper(message[++i])) != 0); // step to the next character
+}
+
+
+//
+// CONTROL PANEL
+//
+
+//
+// M_Responder
+//
+boolean M_Responder (event_t* ev)
+{
+ int ch;
+ int key;
+ 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;
+
+ // In testcontrols mode, none of the function keys should do anything
+ // - the only key is escape to quit.
+
+ if (testcontrols)
+ {
+ if (ev->type == ev_quit
+ || (ev->type == ev_keydown
+ && (ev->data1 == key_menu_activate || ev->data1 == key_menu_quit)))
+ {
+ I_Quit();
+ return true;
+ }
+
+ return false;
+ }
+
+ // "close" button pressed on window?
+ if (ev->type == ev_quit)
+ {
+ // First click on close button = bring up quit confirm message.
+ // Second click on close button = confirm quit
+
+ if (menuactive && messageToPrint && messageRoutine == M_QuitResponse)
+ {
+ M_QuitResponse(key_menu_confirm);
+ }
+ else
+ {
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuitStrife(0);
+ }
+
+ return true;
+ }
+
+ // key is the key pressed, ch is the actual character typed
+
+ ch = 0;
+ key = -1;
+
+ if (ev->type == ev_joystick && joywait < I_GetTime())
+ {
+ if (ev->data3 < 0)
+ {
+ key = key_menu_up;
+ joywait = I_GetTime() + 5;
+ }
+ else if (ev->data3 > 0)
+ {
+ key = key_menu_down;
+ joywait = I_GetTime() + 5;
+ }
+
+ if (ev->data2 < 0)
+ {
+ key = key_menu_left;
+ joywait = I_GetTime() + 2;
+ }
+ else if (ev->data2 > 0)
+ {
+ key = key_menu_right;
+ joywait = I_GetTime() + 2;
+ }
+
+ if (ev->data1&1)
+ {
+ key = key_menu_forward;
+ joywait = I_GetTime() + 5;
+ }
+ if (ev->data1&2)
+ {
+ key = key_menu_back;
+ joywait = I_GetTime() + 5;
+ }
+ }
+ else
+ {
+ if (ev->type == ev_mouse && mousewait < I_GetTime())
+ {
+ mousey += ev->data3;
+ if (mousey < lasty-30)
+ {
+ key = key_menu_down;
+ mousewait = I_GetTime() + 5;
+ mousey = lasty -= 30;
+ }
+ else if (mousey > lasty+30)
+ {
+ key = key_menu_up;
+ mousewait = I_GetTime() + 5;
+ mousey = lasty += 30;
+ }
+
+ mousex += ev->data2;
+ if (mousex < lastx-30)
+ {
+ key = key_menu_left;
+ mousewait = I_GetTime() + 5;
+ mousex = lastx -= 30;
+ }
+ else if (mousex > lastx+30)
+ {
+ key = key_menu_right;
+ mousewait = I_GetTime() + 5;
+ mousex = lastx += 30;
+ }
+
+ if (ev->data1&1)
+ {
+ key = key_menu_forward;
+ mousewait = I_GetTime() + 15;
+ mouse_fire_countdown = 5; // villsa [STRIFE]
+ }
+
+ if (ev->data1&2)
+ {
+ key = key_menu_back;
+ mousewait = I_GetTime() + 15;
+ }
+ }
+ else
+ {
+ if (ev->type == ev_keydown)
+ {
+ key = ev->data1;
+ ch = ev->data2;
+ }
+ }
+ }
+
+ if (key == -1)
+ return false;
+
+ // Save Game string input
+ if (saveStringEnter)
+ {
+ switch(key)
+ {
+ case KEY_BACKSPACE:
+ if (saveCharIndex > 0)
+ {
+ saveCharIndex--;
+ savegamestrings[quickSaveSlot][saveCharIndex] = 0;
+ }
+ break;
+
+ case KEY_ESCAPE:
+ saveStringEnter = 0;
+ strcpy(&savegamestrings[quickSaveSlot][0],saveOldString);
+ break;
+
+ case KEY_ENTER:
+ // [STRIFE]
+ saveStringEnter = 0;
+ if(gameversion == exe_strife_1_31 && !namingCharacter)
+ {
+ // In 1.31, we can be here as a result of normal saving again,
+ // whereas in 1.2 this only ever happens when naming your
+ // character to begin a new game.
+ M_DoSave(quickSaveSlot);
+ return true;
+ }
+ if (savegamestrings[quickSaveSlot][0])
+ M_DoNameChar(quickSaveSlot);
+ break;
+
+ default:
+ // Entering a character - use the 'ch' value, not the key
+
+ ch = toupper(ch);
+
+ if (ch != ' '
+ && (ch - HU_FONTSTART < 0 || ch - HU_FONTSTART >= HU_FONTSIZE))
+ {
+ break;
+ }
+
+ if (ch >= 32 && ch <= 127 &&
+ saveCharIndex < SAVESTRINGSIZE-1 &&
+ M_StringWidth(savegamestrings[quickSaveSlot]) <
+ (SAVESTRINGSIZE-2)*8)
+ {
+ savegamestrings[quickSaveSlot][saveCharIndex++] = ch;
+ savegamestrings[quickSaveSlot][saveCharIndex] = 0;
+ }
+ break;
+ }
+ return true;
+ }
+
+ // Take care of any messages that need input
+ if (messageToPrint)
+ {
+ if (messageNeedsInput)
+ {
+ if (key != ' ' && key != KEY_ESCAPE
+ && key != key_menu_confirm && key != key_menu_abort)
+ {
+ return false;
+ }
+ }
+
+ menuactive = messageLastMenuActive;
+ messageToPrint = 0;
+ if (messageRoutine)
+ messageRoutine(key);
+
+ menupause = false; // [STRIFE] unpause
+ menuactive = false;
+ S_StartSound(NULL, sfx_mtalht); // [STRIFE] sound
+ return true;
+ }
+
+ // [STRIFE]:
+ // * In v1.2 this is moved to F9 (quickload)
+ // * In v1.31 it is moved to F12 with DM spy, and quicksave
+ // functionality is restored separate from normal saving
+ /*
+ if (devparm && key == key_menu_help)
+ {
+ G_ScreenShot ();
+ return true;
+ }
+ */
+
+ // F-Keys
+ if (!menuactive)
+ {
+ if (key == key_menu_decscreen) // Screen size down
+ {
+ if (automapactive || chat_on)
+ return false;
+ M_SizeDisplay(0);
+ S_StartSound(NULL, sfx_stnmov);
+ return true;
+ }
+ else if (key == key_menu_incscreen) // Screen size up
+ {
+ if (automapactive || chat_on)
+ return false;
+ M_SizeDisplay(1);
+ S_StartSound(NULL, sfx_stnmov);
+ return true;
+ }
+ else if (key == key_menu_help) // Help key
+ {
+ M_StartControlPanel ();
+ // haleyjd 08/29/10: [STRIFE] always ReadDef1
+ currentMenu = &ReadDef1;
+
+ itemOn = 0;
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ else if (key == key_menu_save) // Save
+ {
+ // [STRIFE]: Hub saves
+ if(gameversion == exe_strife_1_31)
+ namingCharacter = false; // just saving normally, in 1.31
+
+ if(netgame || players[consoleplayer].health <= 0 ||
+ players[consoleplayer].cheats & CF_ONFIRE)
+ {
+ S_StartSound(NULL, sfx_oof);
+ }
+ else
+ {
+ M_StartControlPanel();
+ S_StartSound(NULL, sfx_swtchn);
+ M_SaveGame(0);
+ }
+ return true;
+ }
+ else if (key == key_menu_load) // Load
+ {
+ // [STRIFE]: Hub saves
+ if(gameversion == exe_strife_1_31)
+ {
+ // 1.31: normal save loading
+ namingCharacter = false;
+ M_StartControlPanel();
+ M_LoadGame(0);
+ S_StartSound(NULL, sfx_swtchn);
+ }
+ else
+ {
+ // Pre 1.31: quickload only
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuickLoad();
+ }
+ return true;
+ }
+ else if (key == key_menu_volume) // Sound Volume
+ {
+ M_StartControlPanel ();
+ currentMenu = &SoundDef;
+ itemOn = sfx_vol;
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ else if (key == key_menu_detail) // Detail toggle
+ {
+ //M_ChangeDetail(0);
+ M_AutoUseHealth(); // [STRIFE]
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ else if (key == key_menu_qsave) // Quicksave
+ {
+ // [STRIFE]: Hub saves
+ if(gameversion == exe_strife_1_31)
+ namingCharacter = false; // for 1.31 save changes
+
+ if(netgame || players[consoleplayer].health <= 0 ||
+ players[consoleplayer].cheats & CF_ONFIRE)
+ {
+ S_StartSound(NULL, sfx_oof);
+ }
+ else
+ {
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuickSave();
+ }
+ return true;
+ }
+ else if (key == key_menu_endgame) // End game
+ {
+ S_StartSound(NULL, sfx_swtchn);
+ M_EndGame(0);
+ return true;
+ }
+ else if (key == key_menu_messages) // Toggle messages
+ {
+ //M_ChangeMessages(0);
+ M_ChangeShowText(); // [STRIFE]
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ else if (key == key_menu_qload) // Quickload
+ {
+ // [STRIFE]
+ // * v1.2: takes a screenshot
+ // * v1.31: does quickload again
+ if(gameversion == exe_strife_1_31)
+ {
+ namingCharacter = false;
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuickLoad();
+ }
+ else
+ G_ScreenShot();
+ return true;
+ }
+ else if (key == key_menu_quit) // Quit DOOM
+ {
+ S_StartSound(NULL, sfx_swtchn);
+ M_QuitStrife(0);
+ return true;
+ }
+ else if (key == key_menu_gamma) // gamma toggle
+ {
+ usegamma++;
+ if (usegamma > 4)
+ usegamma = 0;
+ players[consoleplayer].message = DEH_String(gammamsg[usegamma]);
+ I_SetPalette (W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE));
+ return true;
+ }
+ else if(gameversion == exe_strife_1_31 && key == key_spy)
+ {
+ // haleyjd 20130301: 1.31 moved screenshots to F12.
+ G_ScreenShot();
+ return true;
+ }
+ }
+
+ // Pop-up menu?
+ if (!menuactive)
+ {
+ if (key == key_menu_activate)
+ {
+ M_StartControlPanel ();
+ S_StartSound(NULL, sfx_swtchn);
+ return true;
+ }
+ return false;
+ }
+
+
+ // Keys usable within menu
+
+ if (key == key_menu_down)
+ {
+ // Move down to next item
+
+ do
+ {
+ if (itemOn+1 > currentMenu->numitems-1)
+ itemOn = 0;
+ else itemOn++;
+ S_StartSound(NULL, sfx_pstop);
+ } while(currentMenu->menuitems[itemOn].status==-1);
+
+ return true;
+ }
+ else if (key == key_menu_up)
+ {
+ // Move back up to previous item
+
+ do
+ {
+ if (!itemOn)
+ itemOn = currentMenu->numitems-1;
+ else itemOn--;
+ S_StartSound(NULL, sfx_pstop);
+ } while(currentMenu->menuitems[itemOn].status==-1);
+
+ return true;
+ }
+ else if (key == key_menu_left)
+ {
+ // Slide slider left
+
+ if (currentMenu->menuitems[itemOn].routine &&
+ currentMenu->menuitems[itemOn].status == 2)
+ {
+ S_StartSound(NULL, sfx_stnmov);
+ currentMenu->menuitems[itemOn].routine(0);
+ }
+ return true;
+ }
+ else if (key == key_menu_right)
+ {
+ // Slide slider right
+
+ if (currentMenu->menuitems[itemOn].routine &&
+ currentMenu->menuitems[itemOn].status == 2)
+ {
+ S_StartSound(NULL, sfx_stnmov);
+ currentMenu->menuitems[itemOn].routine(1);
+ }
+ return true;
+ }
+ else if (key == key_menu_forward)
+ {
+ // Activate menu item
+
+ 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_swish); [STRIFE] No sound is played here.
+ }
+ }
+ return true;
+ }
+ else if (key == key_menu_activate)
+ {
+ // Deactivate menu
+ if(gameversion == exe_strife_1_31) // [STRIFE]: 1.31 saving
+ namingCharacter = false;
+
+ if(menuindialog) // [STRIFE] - Get out of dialog engine semi-gracefully
+ P_DialogDoChoice(-1);
+
+ currentMenu->lastOn = itemOn;
+ M_ClearMenus (0);
+ S_StartSound(NULL, sfx_mtalht); // villsa [STRIFE]: sounds
+ return true;
+ }
+ else if (key == key_menu_back)
+ {
+ // Go back to previous menu
+
+ currentMenu->lastOn = itemOn;
+ if (currentMenu->prevMenu)
+ {
+ currentMenu = currentMenu->prevMenu;
+ itemOn = currentMenu->lastOn;
+ S_StartSound(NULL, sfx_swtchn);
+ }
+ return true;
+ }
+ else if (ch != 0)
+ {
+ // Keyboard shortcut?
+
+ 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;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+
+//
+// M_StartControlPanel
+//
+void M_StartControlPanel (void)
+{
+ // intro might call this repeatedly
+ if (menuactive)
+ return;
+
+ menuactive = 1;
+ menupause = true;
+ 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 int i;
+ unsigned int max;
+ char string[80];
+ char *name;
+ int start;
+
+ inhelpscreens = false;
+
+ // Horiz. & Vertically center string and print it.
+ if (messageToPrint)
+ {
+ start = 0;
+ y = 100 - M_StringHeight(messageString) / 2;
+ while (messageString[start] != '\0')
+ {
+ int foundnewline = 0;
+
+ for (i = 0; i < strlen(messageString + start); i++)
+ if (messageString[start + i] == '\n')
+ {
+ memset(string, 0, sizeof(string));
+ strncpy(string, messageString + start, i);
+ foundnewline = 1;
+ start += i + 1;
+ break;
+ }
+
+ if (!foundnewline)
+ {
+ strcpy(string, messageString + start);
+ start += strlen(string);
+ }
+
+ 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++)
+ {
+ name = DEH_String(currentMenu->menuitems[i].name);
+
+ if (name[0])
+ {
+ V_DrawPatchDirect (x, y, W_CacheLumpName(name, PU_CACHE));
+ }
+ y += LINEHEIGHT;
+ }
+
+
+ // haleyjd 08/27/10: [STRIFE] Adjust to draw spinning Sigil
+ // DRAW SIGIL
+ V_DrawPatchDirect(x + CURSORXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT,
+ W_CacheLumpName(DEH_String(cursorName[whichCursor]),
+ PU_CACHE));
+
+}
+
+
+//
+// M_ClearMenus
+//
+// haleyjd 08/28/10: [STRIFE] Added an int param so this can be called by menus.
+// 09/08/10: Added menupause.
+//
+void M_ClearMenus (int choice)
+{
+ choice = 0; // haleyjd: for no warning; not from decompilation.
+ menuactive = 0;
+ menupause = 0;
+}
+
+
+
+
+//
+// M_SetupNextMenu
+//
+void M_SetupNextMenu(menu_t *menudef)
+{
+ currentMenu = menudef;
+ itemOn = currentMenu->lastOn;
+}
+
+
+//
+// M_Ticker
+//
+// haleyjd 08/27/10: [STRIFE] Rewritten for Sigil cursor
+//
+void M_Ticker (void)
+{
+ if (--cursorAnimCounter <= 0)
+ {
+ whichCursor = (whichCursor + 1) % 8;
+ cursorAnimCounter = 5;
+ }
+}
+
+
+//
+// M_Init
+//
+// haleyjd 08/27/10: [STRIFE] Removed DOOM gamemode stuff
+//
+void M_Init (void)
+{
+ currentMenu = &MainDef;
+ menuactive = 0;
+ itemOn = currentMenu->lastOn;
+ whichCursor = 0;
+ cursorAnimCounter = 10;
+ screenSize = screenblocks - 3;
+ messageToPrint = 0;
+ messageString = NULL;
+ messageLastMenuActive = menuactive; // STRIFE-FIXME: assigns 0 here...
+ quickSaveSlot = -1;
+
+ // [STRIFE]: Initialize savegame paths and clear temporary directory
+ G_WriteSaveName(5, "ME");
+ ClearTmp();
+
+ // Here we could catch other version dependencies,
+ // like HELP1/2, and four episodes.
+}
+
diff --git a/src/strife/m_menu.h b/src/strife/m_menu.h
new file mode 100644
index 00000000..cc437384
--- /dev/null
+++ b/src/strife/m_menu.h
@@ -0,0 +1,109 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// Menu widget stuff, episode selection and such.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __M_MENU__
+#define __M_MENU__
+
+#include "d_event.h"
+
+//
+// MENU TYPEDEFS
+//
+
+// haleyjd 09/04/10: [STRIFE] Made external
+
+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)(); // draw routine
+ short x;
+ short y; // x,y of menu
+ short lastOn; // last item user was on in menu
+} menu_t;
+
+extern menu_t* currentMenu; // villsa [STRIFE] made external
+extern short itemOn;
+
+//
+// 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);
+
+// haleyjd 09/04/10: Externalized. Draws menu text.
+int M_WriteText(int x, int y, const char *string);
+
+// haleyjd 09/04/10: [STRIFE] New function.
+void M_DialogDimMsg(int x, int y, char *str, boolean useyfont);
+
+// haleyjd [STRIFE] Externalized
+void M_ClearMenus (int choice);
+void M_LoadSelect(int choice);
+
+extern int detailLevel;
+extern int screenblocks;
+
+#endif
diff --git a/src/strife/m_random.c b/src/strife/m_random.c
new file mode 100644
index 00000000..b7e6aa05
--- /dev/null
+++ b/src/strife/m_random.c
@@ -0,0 +1,88 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <time.h>
+
+#include "m_random.h"
+
+//
+// M_Random
+// Returns a 0-255 number
+//
+
+static const unsigned char rndtable[256] = {
+ 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
+};
+
+int rndindex = 0;
+int prndindex = 0;
+
+// Which one is deterministic?
+int P_Random (void)
+{
+ prndindex = (prndindex+1)&0xff;
+ return rndtable[prndindex];
+}
+
+int M_Random (void)
+{
+ rndindex = (rndindex+1)&0xff;
+ return rndtable[rndindex];
+}
+
+//
+// M_ClearRandom
+//
+// haleyjd 20110204 [STRIFE]: No "seeding" of M_Random index
+//
+void M_ClearRandom (void)
+{
+ prndindex = 0;
+ rndindex = 0;
+}
+
+
+
+
diff --git a/src/strife/m_random.h b/src/strife/m_random.h
new file mode 100644
index 00000000..be778362
--- /dev/null
+++ b/src/strife/m_random.h
@@ -0,0 +1,47 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+//
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __M_RANDOM__
+#define __M_RANDOM__
+
+
+#include "doomtype.h"
+
+
+
+// Returns a number from 0 to 255,
+// from a lookup table.
+int M_Random (void);
+
+// As M_Random, but used only by the play simulation.
+int P_Random (void);
+
+// Fix randoms for demos.
+void M_ClearRandom (void);
+
+
+#endif
diff --git a/src/strife/m_saves.c b/src/strife/m_saves.c
new file mode 100644
index 00000000..a4068c4f
--- /dev/null
+++ b/src/strife/m_saves.c
@@ -0,0 +1,538 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// 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:
+//
+// [STRIFE] New Module
+//
+// Strife Hub Saving Code
+//
+//-----------------------------------------------------------------------------
+
+// For GNU C and POSIX targets, dirent.h should be available. Otherwise, for
+// Visual C++, we need to include the win_opendir module.
+#if defined(_MSC_VER)
+#include <win_opendir.h>
+#elif defined(__GNUC__) || defined(POSIX)
+#include <dirent.h>
+#else
+#error Need an include for dirent.h!
+#endif
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "z_zone.h"
+#include "i_system.h"
+#include "d_player.h"
+#include "deh_str.h"
+#include "doomstat.h"
+#include "m_misc.h"
+#include "m_saves.h"
+#include "p_dialog.h"
+
+//
+// File Paths
+//
+// Strife maintains multiple file paths related to savegames.
+//
+char *savepath; // The actual path of the selected saveslot
+char *savepathtemp; // The path of the temporary saveslot (strfsav6.ssg)
+char *loadpath; // Path used while loading the game
+
+char character_name[CHARACTER_NAME_LEN]; // Name of "character" for saveslot
+
+//
+// ClearTmp
+//
+// Clear the temporary save directory
+//
+void ClearTmp(void)
+{
+ DIR *sp2dir = NULL;
+ struct dirent *f = NULL;
+
+ if(savepathtemp == NULL)
+ I_Error("you fucked up savedir man!");
+
+ if(!(sp2dir = opendir(savepathtemp)))
+ I_Error("ClearTmp: Couldn't open dir %s", savepathtemp);
+
+ while((f = readdir(sp2dir)))
+ {
+ char *filepath = NULL;
+
+ // haleyjd: skip "." and ".." without assuming they're the
+ // first two entries like the original code did.
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ filepath = M_SafeFilePath(savepathtemp, f->d_name);
+ remove(filepath);
+
+ Z_Free(filepath);
+ }
+
+ closedir(sp2dir);
+}
+
+//
+// ClearSlot
+//
+// Clear a single save slot folder
+//
+void ClearSlot(void)
+{
+ DIR *spdir = NULL;
+ struct dirent *f = NULL;
+
+ if(savepath == NULL)
+ I_Error("userdir is fucked up man!");
+
+ if(!(spdir = opendir(savepath)))
+ I_Error("ClearSlot: Couldn't open dir %s", savepath);
+
+ while((f = readdir(spdir)))
+ {
+ char *filepath = NULL;
+
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ filepath = M_SafeFilePath(savepath, f->d_name);
+ remove(filepath);
+
+ Z_Free(filepath);
+ }
+
+ closedir(spdir);
+}
+
+//
+// FromCurr
+//
+// Copying files from savepathtemp to savepath
+//
+void FromCurr(void)
+{
+ DIR *sp2dir = NULL;
+ struct dirent *f = NULL;
+
+ if(!(sp2dir = opendir(savepathtemp)))
+ I_Error("FromCurr: Couldn't open dir %s", savepathtemp);
+
+ while((f = readdir(sp2dir)))
+ {
+ byte *filebuffer = NULL;
+ int filelen = 0;
+ char *srcfilename = NULL;
+ char *dstfilename = NULL;
+
+ // haleyjd: skip "." and ".." without assuming they're the
+ // first two entries like the original code did.
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, NOT sprintf.
+ srcfilename = M_SafeFilePath(savepathtemp, f->d_name);
+ dstfilename = M_SafeFilePath(savepath, f->d_name);
+
+ filelen = M_ReadFile(srcfilename, &filebuffer);
+ M_WriteFile(dstfilename, filebuffer, filelen);
+
+ Z_Free(filebuffer);
+ Z_Free(srcfilename);
+ Z_Free(dstfilename);
+ }
+
+ closedir(sp2dir);
+}
+
+//
+// ToCurr
+//
+// Copying files from savepath to savepathtemp
+//
+void ToCurr(void)
+{
+ DIR *spdir = NULL;
+ struct dirent *f = NULL;
+
+ ClearTmp();
+
+ // BUG: Rogue copypasta'd this error message, which is why we don't know
+ // the real original name of this function.
+ if(!(spdir = opendir(savepath)))
+ I_Error("ClearSlot: Couldn't open dir %s", savepath);
+
+ while((f = readdir(spdir)))
+ {
+ byte *filebuffer = NULL;
+ int filelen = 0;
+ char *srcfilename = NULL;
+ char *dstfilename = NULL;
+
+ if(!strcmp(f->d_name, ".") || !strcmp(f->d_name, ".."))
+ continue;
+
+ // haleyjd: use M_SafeFilePath, NOT sprintf.
+ srcfilename = M_SafeFilePath(savepath, f->d_name);
+ dstfilename = M_SafeFilePath(savepathtemp, f->d_name);
+
+ filelen = M_ReadFile(srcfilename, &filebuffer);
+ M_WriteFile(dstfilename, filebuffer, filelen);
+
+ Z_Free(filebuffer);
+ Z_Free(srcfilename);
+ Z_Free(dstfilename);
+ }
+
+ closedir(spdir);
+}
+
+//
+// M_SaveMoveMapToHere
+//
+// Moves a map to the "HERE" save.
+//
+void M_SaveMoveMapToHere(void)
+{
+ char *mapsave = NULL;
+ char *heresave = NULL;
+ char tmpnum[33];
+
+ // haleyjd: no itoa available...
+ memset(tmpnum, 0, sizeof(tmpnum));
+ sprintf(tmpnum, "%d", gamemap);
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ mapsave = M_SafeFilePath(savepath, tmpnum);
+ heresave = M_SafeFilePath(savepath, "here");
+
+ // haleyjd: use M_FileExists, not access
+ if(M_FileExists(mapsave))
+ {
+ remove(heresave);
+ rename(mapsave, heresave);
+ }
+
+ Z_Free(mapsave);
+ Z_Free(heresave);
+}
+
+//
+// M_SaveMoveHereToMap
+//
+// Moves the "HERE" save to a map.
+//
+void M_SaveMoveHereToMap(void)
+{
+ char *mapsave = NULL;
+ char *heresave = NULL;
+ char tmpnum[33];
+
+ // haleyjd: no itoa available...
+ memset(tmpnum, 0, sizeof(tmpnum));
+ sprintf(tmpnum, "%d", gamemap);
+
+ mapsave = M_SafeFilePath(savepathtemp, tmpnum);
+ heresave = M_SafeFilePath(savepathtemp, "here");
+
+ if(M_FileExists(heresave))
+ {
+ remove(mapsave);
+ rename(heresave, mapsave);
+ }
+
+ Z_Free(mapsave);
+ Z_Free(heresave);
+}
+
+//
+// M_SaveMisObj
+//
+// Writes the mission objective into the MIS_OBJ file.
+//
+boolean M_SaveMisObj(const char *path)
+{
+ boolean result;
+ char *destpath = NULL;
+
+ // haleyjd 20110210: use M_SafeFilePath, not sprintf
+ destpath = M_SafeFilePath(path, "mis_obj");
+ result = M_WriteFile(destpath, mission_objective, OBJECTIVE_LEN);
+
+ Z_Free(destpath);
+ return result;
+}
+
+//
+// M_ReadMisObj
+//
+// Reads the mission objective from the MIS_OBJ file.
+//
+void M_ReadMisObj(void)
+{
+ FILE *f = NULL;
+ char *srcpath = NULL;
+
+ // haleyjd: use M_SafeFilePath, not sprintf
+ srcpath = M_SafeFilePath(savepathtemp, "mis_obj");
+
+ if((f = fopen(srcpath, "rb")))
+ {
+ fread(mission_objective, 1, OBJECTIVE_LEN, f);
+ fclose(f);
+ }
+
+ Z_Free(srcpath);
+}
+
+//=============================================================================
+//
+// Original Routines
+//
+// haleyjd - None of the below code is derived from Strife itself, but has been
+// adapted or created in order to provide secure, portable filepath handling
+// for the purposes of savegame support. This is partially needed to allow for
+// differences in Choco due to it being multiplatform. The rest exists because
+// I cannot stand programming in an impoverished ANSI C environment that
+// calls sprintf on fixed-size buffers. :P
+//
+
+//
+// M_Calloc
+//
+// haleyjd 20110210 - original routine
+// Because Choco doesn't have Z_Calloc O_o
+//
+void *M_Calloc(size_t n1, size_t n2)
+{
+ return (n1 *= n2) ? memset(Z_Malloc(n1, PU_STATIC, NULL), 0, n1) : NULL;
+}
+
+//
+// M_StringAlloc
+//
+// haleyjd: This routine takes any number of strings and a number of extra
+// characters, calculates their combined length, and calls Z_Alloca to create
+// a temporary buffer of that size. This is extremely useful for allocation of
+// file paths, and is used extensively in d_main.c. The pointer returned is
+// to a temporary Z_Alloca buffer, which lives until the next main loop
+// iteration, so don't cache it. Note that this idiom is not possible with the
+// normal non-standard alloca function, which allocates stack space.
+//
+// [STRIFE] - haleyjd 20110210
+// This routine is taken from the Eternity Engine and adapted to do without
+// Z_Alloca. I need secure string concatenation for filepath handling. The
+// only difference from use in EE is that the pointer returned in *str must
+// be manually freed.
+//
+int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...)
+{
+ va_list args;
+ size_t len = extra;
+
+ if(numstrs < 1)
+ I_Error("M_StringAlloc: invalid input\n");
+
+ len += strlen(str1);
+
+ --numstrs;
+
+ if(numstrs != 0)
+ {
+ va_start(args, str1);
+
+ while(numstrs != 0)
+ {
+ const char *argstr = va_arg(args, const char *);
+
+ len += strlen(argstr);
+
+ --numstrs;
+ }
+
+ va_end(args);
+ }
+
+ ++len;
+
+ *str = (char *)(M_Calloc(1, len));
+
+ return len;
+}
+
+//
+// M_NormalizeSlashes
+//
+// Remove trailing slashes, translate backslashes to slashes
+// The string to normalize is passed and returned in str
+//
+// killough 11/98: rewritten
+//
+// [STRIFE] - haleyjd 20110210: Borrowed from Eternity and adapted to respect
+// the DIR_SEPARATOR define used by Choco Doom. This routine originated in
+// BOOM.
+//
+void M_NormalizeSlashes(char *str)
+{
+ char *p;
+
+ // Convert all slashes/backslashes to DIR_SEPARATOR
+ for(p = str; *p; p++)
+ {
+ if((*p == '/' || *p == '\\') && *p != DIR_SEPARATOR)
+ *p = DIR_SEPARATOR;
+ }
+
+ // Remove trailing slashes
+ while(p > str && *--p == DIR_SEPARATOR)
+ *p = 0;
+
+ // Collapse multiple slashes
+ for(p = str; (*str++ = *p); )
+ if(*p++ == DIR_SEPARATOR)
+ while(*p == DIR_SEPARATOR)
+ p++;
+}
+
+//
+// M_SafeFilePath
+//
+// haleyjd 20110210 - original routine.
+// This routine performs safe, portable concatenation of a base file path
+// with another path component or file name. The returned string is Z_Malloc'd
+// and should be freed when it has exhausted its usefulness.
+//
+char *M_SafeFilePath(const char *basepath, const char *newcomponent)
+{
+ int newstrlen = 0;
+ char *newstr = NULL;
+
+ if (!strcmp(basepath, ""))
+ {
+ basepath = ".";
+ }
+
+ // Always throw in a slash. M_NormalizeSlashes will remove it in the case
+ // that either basepath or newcomponent includes a redundant slash at the
+ // end or beginning respectively.
+ newstrlen = M_StringAlloc(&newstr, 3, 1, basepath, "/", newcomponent);
+ snprintf(newstr, newstrlen, "%s/%s", basepath, newcomponent);
+ M_NormalizeSlashes(newstr);
+
+ return newstr;
+}
+
+//
+// M_CreateSaveDirs
+//
+// haleyjd 20110210: Vanilla Strife went tits-up if it didn't have the full set
+// of save folders which were created externally by the installer. fraggle says
+// that's no good for Choco purposes, and I agree, so this routine will create
+// the full set of folders under the configured savegamedir.
+//
+void M_CreateSaveDirs(const char *savedir)
+{
+ int i;
+
+ for(i = 0; i < 7; i++)
+ {
+ char *compositedir;
+
+ // compose the full path by concatenating with savedir
+ compositedir = M_SafeFilePath(savedir, M_MakeStrifeSaveDir(i, ""));
+
+ M_MakeDirectory(compositedir);
+
+ Z_Free(compositedir);
+ }
+}
+
+//
+// M_MakeStrifeSaveDir
+//
+// haleyjd 20110211: Convenience routine
+//
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra)
+{
+ static char tmpbuffer[32];
+
+ memset(tmpbuffer, 0, sizeof(tmpbuffer));
+ sprintf(tmpbuffer, "strfsav%d.ssg%s", slotnum, extra);
+
+ return tmpbuffer;
+}
+
+//
+// M_GetFilePath
+//
+// haleyjd: STRIFE-FIXME: Temporary?
+// Code borrowed from Eternity, and modified to return separator char
+//
+char M_GetFilePath(const char *fn, char *dest, size_t len)
+{
+ boolean found_slash = false;
+ char *p;
+ char sepchar = '\0';
+
+ memset(dest, 0, len);
+
+ p = dest + len - 1;
+
+ strncpy(dest, fn, len);
+
+ while(p >= dest)
+ {
+ if(*p == '/' || *p == '\\')
+ {
+ sepchar = *p;
+ found_slash = true; // mark that the path ended with a slash
+ *p = '\0';
+ break;
+ }
+ *p = '\0';
+ p--;
+ }
+
+ // haleyjd: in the case that no slash was ever found, yet the
+ // path string is empty, we are dealing with a file local to the
+ // working directory. The proper path to return for such a string is
+ // not "", but ".", since the format strings add a slash now. When
+ // the string is empty but a slash WAS found, we really do want to
+ // return the empty string, since the path is relative to the root.
+ if(!found_slash && *dest == '\0')
+ *dest = '.';
+
+ // if a separator is not found, default to forward, because Windows
+ // supports that too.
+ if(sepchar == '\0')
+ sepchar = '/';
+
+ return sepchar;
+}
+
+// EOF
+
+
diff --git a/src/strife/m_saves.h b/src/strife/m_saves.h
new file mode 100644
index 00000000..59941850
--- /dev/null
+++ b/src/strife/m_saves.h
@@ -0,0 +1,64 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villareal
+//
+// 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:
+//
+// [STRIFE] New Module
+//
+// Strife Hub Saving Code
+//
+//-----------------------------------------------------------------------------
+
+#ifndef M_SAVES_H__
+#define M_SAVES_H__
+
+#define CHARACTER_NAME_LEN 32
+
+extern char *savepath;
+extern char *savepathtemp;
+extern char *loadpath;
+extern char character_name[CHARACTER_NAME_LEN];
+
+// Strife Savegame Functions
+void ClearTmp(void);
+void ClearSlot(void);
+void FromCurr(void);
+void ToCurr(void);
+void M_SaveMoveMapToHere(void);
+void M_SaveMoveHereToMap(void);
+
+boolean M_SaveMisObj(const char *path);
+void M_ReadMisObj(void);
+
+// Custom Utilities for Filepath Handling
+void *M_Calloc(size_t n1, size_t n2);
+void M_NormalizeSlashes(char *str);
+int M_StringAlloc(char **str, int numstrs, size_t extra, const char *str1, ...);
+char *M_SafeFilePath(const char *basepath, const char *newcomponent);
+char M_GetFilePath(const char *fn, char *dest, size_t len);
+char *M_MakeStrifeSaveDir(int slotnum, const char *extra);
+void M_CreateSaveDirs(const char *savedir);
+
+#endif
+
+// EOF
+
+
diff --git a/src/strife/p_ceilng.c b/src/strife/p_ceilng.c
new file mode 100644
index 00000000..fce4dce2
--- /dev/null
+++ b/src/strife/p_ceilng.c
@@ -0,0 +1,351 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 "z_zone.h"
+#include "doomdef.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "sounds.h"
+
+//
+// CEILINGS
+//
+
+
+ceiling_t* activeceilings[MAXCEILINGS];
+
+
+//
+// T_MoveCeiling
+//
+
+void T_MoveCeiling (ceiling_t* ceiling)
+{
+ result_e res;
+
+ switch(ceiling->direction)
+ {
+ case 0:
+ // IN STASIS
+ break;
+ case 1:
+ // UP
+ res = T_MovePlane(ceiling->sector,
+ ceiling->speed,
+ ceiling->topheight,
+ false,1,ceiling->direction);
+
+ if (!(leveltime&7))
+ {
+ switch(ceiling->type)
+ {
+ case silentCrushAndRaise:
+ break;
+ default:
+ S_StartSound(&ceiling->sector->soundorg, sfx_stnmov);
+ // ?
+ break;
+ }
+ }
+
+ if (res == pastdest)
+ {
+ switch(ceiling->type)
+ {
+ case raiseToHighest:
+ P_RemoveActiveCeiling(ceiling);
+ break;
+
+ case silentCrushAndRaise:
+ S_StartSound(&ceiling->sector->soundorg, sfx_pstop);
+ case fastCrushAndRaise:
+ case crushAndRaise:
+ ceiling->direction = -1;
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ break;
+
+ case -1:
+ // DOWN
+ res = T_MovePlane(ceiling->sector,
+ ceiling->speed,
+ ceiling->bottomheight,
+ ceiling->crush,1,ceiling->direction);
+
+ if (!(leveltime&7))
+ {
+ switch(ceiling->type)
+ {
+ case silentCrushAndRaise: break;
+ default:
+ S_StartSound(&ceiling->sector->soundorg, sfx_stnmov);
+ }
+ }
+
+ if (res == pastdest)
+ {
+ switch(ceiling->type)
+ {
+ case silentCrushAndRaise:
+ S_StartSound(&ceiling->sector->soundorg, sfx_pstop);
+ case crushAndRaise:
+ ceiling->speed = CEILSPEED;
+ case fastCrushAndRaise:
+ ceiling->direction = 1;
+ break;
+
+ case lowerAndCrush:
+ case lowerToFloor:
+ P_RemoveActiveCeiling(ceiling);
+ break;
+
+ default:
+ break;
+ }
+ }
+ else // ( res != pastdest )
+ {
+ if (res == crushed)
+ {
+ switch(ceiling->type)
+ {
+ case silentCrushAndRaise:
+ case crushAndRaise:
+ case lowerAndCrush:
+ ceiling->speed = CEILSPEED / 8;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ }
+}
+
+
+//
+// EV_DoCeiling
+// Move a ceiling up/down and all around!
+//
+// haleyjd 10/04/10: [STRIFE] Changes:
+// * Fast crushers were made 2x as fast.
+// * lowerAndCrush was apparently "fixed" to actually crush, and was also
+// altered to lower all the way to the floor rather than remain 8 above.
+// * silentCrushAndRaise and crushAndRaise no longer crush.
+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.
+ switch(type)
+ {
+ case fastCrushAndRaise:
+ case silentCrushAndRaise:
+ case crushAndRaise:
+ P_ActivateInStasisCeiling(line);
+ default:
+ break;
+ }
+
+ while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if (sec->specialdata)
+ continue;
+
+ // new door thinker
+ rtn = 1;
+ ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
+ P_AddThinker (&ceiling->thinker);
+ sec->specialdata = ceiling;
+ ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
+ ceiling->sector = sec;
+ ceiling->crush = false;
+
+ switch(type)
+ {
+ case fastCrushAndRaise:
+ // [STRIFE]: Speed of fast crushers increased by 2x!
+ ceiling->crush = true;
+ ceiling->topheight = sec->ceilingheight;
+ ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
+ ceiling->direction = -1;
+ ceiling->speed = CEILSPEED * 4; // [STRIFE] Was CEILSPEED * 2
+ break;
+
+ case lowerAndCrush:
+ // [STRIFE] lowerAndCrush doesn't seem to have crushed in DOOM,
+ // but it was certainly made to do so in Strife! It is also
+ // changed to lower all the way to the floor.
+ ceiling->crush = 1;
+ ceiling->direction = -1;
+ ceiling->speed = CEILSPEED;
+ ceiling->bottomheight = sec->floorheight;
+ break;
+
+ case silentCrushAndRaise:
+ case crushAndRaise:
+ // [STRIFE] haleyjd 20130209: Turns out these types do NOT crush
+ // in Strife... yeah, that makes a lot of sense. Thanks to Gez for
+ // having detected this difference.
+ //ceiling->crush = true;
+ ceiling->topheight = sec->ceilingheight;
+
+ 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;
+ }
+
+ ceiling->tag = sec->tag;
+ ceiling->type = type;
+ P_AddActiveCeiling(ceiling);
+ }
+ return rtn;
+}
+
+
+//
+// Add an active ceiling
+//
+void P_AddActiveCeiling(ceiling_t* c)
+{
+ int i;
+
+ for (i = 0; i < MAXCEILINGS;i++)
+ {
+ if (activeceilings[i] == NULL)
+ {
+ activeceilings[i] = c;
+ return;
+ }
+ }
+}
+
+
+
+//
+// Remove a ceiling's thinker
+//
+void P_RemoveActiveCeiling(ceiling_t* c)
+{
+ int i;
+
+ for (i = 0;i < MAXCEILINGS;i++)
+ {
+ if (activeceilings[i] == c)
+ {
+ activeceilings[i]->sector->specialdata = NULL;
+ P_RemoveThinker (&activeceilings[i]->thinker);
+ activeceilings[i] = NULL;
+ break;
+ }
+ }
+}
+
+
+
+//
+// Restart a ceiling that's in-stasis
+//
+void P_ActivateInStasisCeiling(line_t* line)
+{
+ int i;
+
+ for (i = 0;i < MAXCEILINGS;i++)
+ {
+ if (activeceilings[i]
+ && (activeceilings[i]->tag == line->tag)
+ && (activeceilings[i]->direction == 0))
+ {
+ activeceilings[i]->direction = activeceilings[i]->olddirection;
+ activeceilings[i]->thinker.function.acp1
+ = (actionf_p1)T_MoveCeiling;
+ }
+ }
+}
+
+
+
+//
+// EV_CeilingCrushStop
+// Stop a ceiling from crushing!
+//
+int EV_CeilingCrushStop(line_t *line)
+{
+ int i;
+ int rtn;
+
+ rtn = 0;
+ for (i = 0;i < MAXCEILINGS;i++)
+ {
+ if (activeceilings[i]
+ && (activeceilings[i]->tag == line->tag)
+ && (activeceilings[i]->direction != 0))
+ {
+ activeceilings[i]->olddirection = activeceilings[i]->direction;
+ activeceilings[i]->thinker.function.acv = (actionf_v)NULL;
+ activeceilings[i]->direction = 0; // in-stasis
+ rtn = 1;
+ }
+ }
+
+
+ return rtn;
+}
diff --git a/src/strife/p_dialog.c b/src/strife/p_dialog.c
new file mode 100644
index 00000000..070288aa
--- /dev/null
+++ b/src/strife/p_dialog.c
@@ -0,0 +1,1420 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villarreal
+//
+// 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:
+//
+// [STRIFE] New Module
+//
+// Dialog Engine for Strife
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "z_zone.h"
+#include "w_wad.h"
+#include "deh_str.h"
+#include "d_main.h"
+#include "d_mode.h"
+#include "d_player.h"
+#include "doomstat.h"
+#include "m_random.h"
+#include "m_menu.h"
+#include "r_main.h"
+#include "v_video.h"
+#include "p_local.h"
+#include "sounds.h"
+#include "p_dialog.h"
+#include "s_sound.h"
+#include "p_local.h"
+#include "p_inter.h"
+
+//
+// Defines and Macros
+//
+
+// haleyjd: size of the original Strife mapdialog_t structure.
+#define ORIG_MAPDIALOG_SIZE 0x5EC
+
+#define DIALOG_INT(field, ptr) \
+ field = ((int)ptr[0] | \
+ ((int)ptr[1] << 8) | \
+ ((int)ptr[2] << 16) | \
+ ((int)ptr[3] << 24)); \
+ ptr += 4;
+
+#define DIALOG_STR(field, ptr, len) \
+ memcpy(field, ptr, len); \
+ ptr += len;
+
+//
+// Globals
+//
+
+// This can be toggled at runtime to determine if the full dialog messages
+// are subtitled on screen or not. Defaults to off.
+int dialogshowtext = false;
+
+// The global mission objective buffer. This gets written to and read from file,
+// and is set by dialogs and line actions.
+char mission_objective[OBJECTIVE_LEN];
+
+//
+// Static Globals
+//
+
+// True if SCRIPT00 is loaded.
+static boolean script0loaded;
+
+// Number of dialogs defined in the current level's script.
+static int numleveldialogs;
+
+// The actual level dialogs. This didn't exist in Strife, but is new to account
+// for structure alignment/packing concerns, given that Chocolate Doom is
+// multiplatform.
+static mapdialog_t *leveldialogs;
+
+// The actual script00 dialogs. As above.
+static mapdialog_t *script0dialogs;
+
+// Number of dialogs defined in the SCRIPT00 lump.
+static int numscript0dialogs;
+
+// The player engaged in dialog. This is always player 1, though, since Rogue
+// never completed the ability to use dialog outside of single-player mode.
+static player_t *dialogplayer;
+
+// The object to which the player is speaking.
+static mobj_t *dialogtalker;
+
+// The talker's current angle
+static angle_t dialogtalkerangle;
+
+// The currently active mapdialog object.
+static mapdialog_t *currentdialog;
+
+// Text at the end of the choices
+static char dialoglastmsgbuffer[48];
+
+// Item to display to player when picked up or recieved
+static char pickupstring[46];
+
+// Health based on gameskill given by the front's medic
+static const int healthamounts[] = { -100 , -75, -50, -50, -100 };
+
+//=============================================================================
+//
+// Dialog State Sets
+//
+// These are used to animate certain actors in response to what happens in
+// their dialog sequences.
+//
+
+typedef struct dialogstateset_s
+{
+ mobjtype_t type; // the type of object
+ statenum_t greet; // greeting state, for start of dialog
+ statenum_t yes; // "yes" state, for an affirmative response
+ statenum_t no; // "no" state, when you don't have the right items
+} dialogstateset_t;
+
+static dialogstateset_t dialogstatesets[] =
+{
+ { MT_PLAYER, S_NULL, S_NULL, S_NULL },
+ { MT_SHOPKEEPER_W, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+ { MT_SHOPKEEPER_B, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+ { MT_SHOPKEEPER_A, S_MRGT_00, S_MRYS_00, S_MRNO_00 },
+ { MT_SHOPKEEPER_M, S_MRGT_00, S_MRYS_00, S_MRNO_00 }
+};
+
+// Rogue stored this in a static global rather than making it a define...
+static int numdialogstatesets = arrlen(dialogstatesets);
+
+// Current dialog talker state
+static dialogstateset_t *dialogtalkerstates;
+
+//=============================================================================
+//
+// Random Messages
+//
+// Rogue hard-coded these so they wouldn't have to repeat them several times
+// in the SCRIPT00 lump, apparently.
+//
+
+#define MAXRNDMESSAGES 10
+
+typedef struct rndmessage_s
+{
+ const char *type_name;
+ int nummessages;
+ char *messages[MAXRNDMESSAGES];
+} rndmessage_t;
+
+static rndmessage_t rndMessages[] =
+{
+ // Peasants
+ {
+ "PEASANT",
+ 10,
+ {
+ "PLEASE DON'T HURT ME.",
+
+ "IF YOU'RE LOOKING TO HURT ME, I'M \n"
+ "NOT REALLY WORTH THE EFFORT.",
+
+ "I DON'T KNOW ANYTHING.",
+
+ "GO AWAY OR I'LL CALL THE GUARDS!",
+
+ "I WISH SOMETIMES THAT ALL THESE \n"
+ "REBELS WOULD JUST LEARN THEIR \n"
+ "PLACE AND STOP THIS NONSENSE.",
+
+ "JUST LEAVE ME ALONE, OK?",
+
+ "I'M NOT SURE, BUT SOMETIMES I THINK \n"
+ "THAT I KNOW SOME OF THE ACOLYTES.",
+
+ "THE ORDER'S GOT EVERYTHING AROUND HERE PRETTY WELL LOCKED UP TIGHT.",
+
+ "THERE'S NO WAY THAT THIS IS JUST A \n"
+ "SECURITY FORCE.",
+
+ "I'VE HEARD THAT THE ORDER IS REALLY \n"
+ "NERVOUS ABOUT THE FRONT'S \n"
+ "ACTIONS AROUND HERE."
+ }
+ },
+ // Rebel
+ {
+ "REBEL",
+ 10,
+ {
+ "THERE'S NO WAY THE ORDER WILL \n"
+ "STAND AGAINST US.",
+
+ "WE'RE ALMOST READY TO STRIKE. \n"
+ "MACIL'S PLANS ARE FALLING IN PLACE.",
+
+ "WE'RE ALL BEHIND YOU, DON'T WORRY.",
+
+ "DON'T GET TOO CLOSE TO ANY OF THOSE BIG ROBOTS. THEY'LL MELT YOU DOWN \n"
+ "FOR SCRAP!",
+
+ "THE DAY OF OUR GLORY WILL SOON \n"
+ "COME, AND THOSE WHO OPPOSE US WILL \n"
+ "BE CRUSHED!",
+
+ "DON'T GET TOO COMFORTABLE. WE'VE \n"
+ "STILL GOT OUR WORK CUT OUT FOR US.",
+
+ "MACIL SAYS THAT YOU'RE THE NEW \n"
+ "HOPE. BEAR THAT IN MIND.",
+
+ "ONCE WE'VE TAKEN THESE CHARLATANS DOWN, WE'LL BE ABLE TO REBUILD THIS "
+ "WORLD AS IT SHOULD BE.",
+
+ "REMEMBER THAT YOU AREN'T FIGHTING \n"
+ "JUST FOR YOURSELF, BUT FOR \n"
+ "EVERYONE HERE AND OUTSIDE.",
+
+ "AS LONG AS ONE OF US STILL STANDS, \n"
+ "WE WILL WIN."
+ }
+ },
+ // Acolyte
+ {
+ "AGUARD",
+ 10,
+ {
+ "MOVE ALONG, PEASANT.",
+
+ "FOLLOW THE TRUE FAITH, ONLY THEN \n"
+ "WILL YOU BEGIN TO UNDERSTAND.",
+
+ "ONLY THROUGH DEATH CAN ONE BE \n"
+ "TRULY REBORN.",
+
+ "I'M NOT INTERESTED IN YOUR USELESS \n"
+ "DRIVEL.",
+
+ "IF I HAD WANTED TO TALK TO YOU I \n"
+ "WOULD HAVE TOLD YOU SO.",
+
+ "GO AND ANNOY SOMEONE ELSE!",
+
+ "KEEP MOVING!",
+
+ "IF THE ALARM GOES OFF, JUST STAY OUT OF OUR WAY!",
+
+ "THE ORDER WILL CLEANSE THE WORLD \n"
+ "AND USHER IT INTO THE NEW ERA.",
+
+ "PROBLEM? NO, I THOUGHT NOT.",
+ }
+ },
+ // Beggar
+ {
+ "BEGGAR",
+ 10,
+ {
+ "ALMS FOR THE POOR?",
+
+ "WHAT ARE YOU LOOKING AT, SURFACER?",
+
+ "YOU WOULDN'T HAVE ANY EXTRA FOOD, WOULD YOU?",
+
+ "YOU SURFACE PEOPLE WILL NEVER \n"
+ " "
+ " UNDERSTAND US.",
+
+ "HA, THE GUARDS CAN'T FIND US. THOSE \n"
+ "IDIOTS DON'T EVEN KNOW WE EXIST.",
+
+ "ONE DAY EVERYONE BUT THOSE WHO SERVE THE ORDER WILL BE FORCED TO "
+ " JOIN US.",
+
+ "STARE NOW, BUT YOU KNOW THAT THIS WILL BE YOUR OWN FACE ONE DAY.",
+
+ // Note: "NOTHING THING" is an authentic typo
+ "THERE'S NOTHING THING MORE \n"
+ "ANNOYING THAN A SURFACER WITH AN ATTITUDE!",
+
+ "THE ORDER WILL MAKE SHORT WORK OF YOUR PATHETIC FRONT.",
+
+ "WATCH YOURSELF SURFACER. WE KNOW OUR ENEMIES!"
+ }
+ },
+ // Templar
+ {
+ "PGUARD",
+ 10,
+ {
+ "WE ARE THE HANDS OF FATE. TO EARN \n"
+ "OUR WRATH IS TO FIND OBLIVION!",
+
+ "THE ORDER WILL CLEANSE THE WORLD \n"
+ "OF THE WEAK AND CORRUPT!",
+
+ "OBEY THE WILL OF THE MASTERS!",
+
+ "LONG LIFE TO THE BROTHERS OF THE \n"
+ "ORDER!",
+
+ "FREE WILL IS AN ILLUSION THAT BINDS \n"
+ "THE WEAK MINDED.",
+
+ "POWER IS THE PATH TO GLORY. TO \n"
+ "FOLLOW THE ORDER IS TO WALK THAT \n"
+ "PATH!",
+
+ "TAKE YOUR PLACE AMONG THE \n"
+ "RIGHTEOUS, JOIN US!",
+
+ "THE ORDER PROTECTS ITS OWN.",
+
+ "ACOLYTES? THEY HAVE YET TO SEE THE FULL GLORY OF THE ORDER.",
+
+ "IF THERE IS ANY HONOR INSIDE THAT \n"
+ "PATHETIC SHELL OF A BODY, \n"
+ "YOU'LL ENTER INTO THE ARMS OF THE \n"
+ "ORDER."
+ }
+ }
+};
+
+// And again, this could have been a define, but was a variable.
+static int numrndmessages = arrlen(rndMessages);
+
+//=============================================================================
+//
+// Dialog Menu Structure
+//
+// The Strife dialog system is actually just a serious abuse of the DOOM menu
+// engine. Hence why it doesn't work in multiplayer games or during demo
+// recording.
+//
+
+#define NUMDIALOGMENUITEMS 6
+
+static void P_DialogDrawer(void);
+
+static menuitem_t dialogmenuitems[] =
+{
+ { 1, "", P_DialogDoChoice, '1' }, // These items are loaded dynamically
+ { 1, "", P_DialogDoChoice, '2' },
+ { 1, "", P_DialogDoChoice, '3' },
+ { 1, "", P_DialogDoChoice, '4' },
+ { 1, "", P_DialogDoChoice, '5' },
+ { 1, "", P_DialogDoChoice, '6' } // Item 6 is always the dismissal item
+};
+
+static menu_t dialogmenu =
+{
+ NUMDIALOGMENUITEMS,
+ NULL,
+ dialogmenuitems,
+ P_DialogDrawer,
+ 42,
+ 75,
+ 0
+};
+
+// Lump number of the dialog background picture, if any.
+static int dialogbgpiclumpnum;
+
+// Name of current speaking character.
+static char *dialogname;
+
+// Current dialog text.
+static const char *dialogtext;
+
+//=============================================================================
+//
+// Routines
+//
+
+//
+// P_ParseDialogLump
+//
+// haleyjd 09/02/10: This is an original function added to parse out the
+// dialogs from the dialog lump rather than reading them raw from the lump
+// pointer. This avoids problems with structure packing.
+//
+static void P_ParseDialogLump(byte *lump, mapdialog_t **dialogs,
+ int numdialogs, int tag)
+{
+ int i;
+ byte *rover = lump;
+
+ *dialogs = Z_Malloc(numdialogs * sizeof(mapdialog_t), tag, NULL);
+
+ for(i = 0; i < numdialogs; i++)
+ {
+ int j;
+ mapdialog_t *curdialog = &((*dialogs)[i]);
+
+ DIALOG_INT(curdialog->speakerid, rover);
+ DIALOG_INT(curdialog->dropitem, rover);
+ DIALOG_INT(curdialog->checkitem[0], rover);
+ DIALOG_INT(curdialog->checkitem[1], rover);
+ DIALOG_INT(curdialog->checkitem[2], rover);
+ DIALOG_INT(curdialog->jumptoconv, rover);
+ DIALOG_STR(curdialog->name, rover, MDLG_NAMELEN);
+ DIALOG_STR(curdialog->voice, rover, MDLG_LUMPLEN);
+ DIALOG_STR(curdialog->backpic, rover, MDLG_LUMPLEN);
+ DIALOG_STR(curdialog->text, rover, MDLG_TEXTLEN);
+
+ // copy choices
+ for(j = 0; j < 5; j++)
+ {
+ mapdlgchoice_t *curchoice = &(curdialog->choices[j]);
+ DIALOG_INT(curchoice->giveitem, rover);
+ DIALOG_INT(curchoice->needitems[0], rover);
+ DIALOG_INT(curchoice->needitems[1], rover);
+ DIALOG_INT(curchoice->needitems[2], rover);
+ DIALOG_INT(curchoice->needamounts[0], rover);
+ DIALOG_INT(curchoice->needamounts[1], rover);
+ DIALOG_INT(curchoice->needamounts[2], rover);
+ DIALOG_STR(curchoice->text, rover, MDLG_CHOICELEN);
+ DIALOG_STR(curchoice->textok, rover, MDLG_MSGLEN);
+ DIALOG_INT(curchoice->next, rover);
+ DIALOG_INT(curchoice->objective, rover);
+ DIALOG_STR(curchoice->textno, rover, MDLG_MSGLEN);
+ }
+ }
+}
+
+//
+// P_DialogLoad
+//
+// [STRIFE] New function
+// haleyjd 09/02/10: Loads the dialog script for the current map. Also loads
+// SCRIPT00 if it has not yet been loaded.
+//
+void P_DialogLoad(void)
+{
+ char lumpname[9];
+ int lumpnum;
+
+ // load the SCRIPTxy lump corresponding to MAPxy, if it exists.
+ DEH_snprintf(lumpname, sizeof(lumpname), "script%02d", gamemap);
+ if((lumpnum = W_CheckNumForName(lumpname)) == -1)
+ numleveldialogs = 0;
+ else
+ {
+ byte *leveldialogptr = W_CacheLumpNum(lumpnum, PU_STATIC);
+ numleveldialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
+ P_ParseDialogLump(leveldialogptr, &leveldialogs, numleveldialogs,
+ PU_LEVEL);
+ Z_Free(leveldialogptr); // haleyjd: free the original lump
+ }
+
+ // also load SCRIPT00 if it has not been loaded yet
+ if(!script0loaded)
+ {
+ byte *script0ptr;
+
+ script0loaded = true;
+ // BUG: Rogue should have used W_GetNumForName here...
+ lumpnum = W_CheckNumForName(DEH_String("script00"));
+ script0ptr = W_CacheLumpNum(lumpnum, PU_STATIC);
+ numscript0dialogs = W_LumpLength(lumpnum) / ORIG_MAPDIALOG_SIZE;
+ P_ParseDialogLump(script0ptr, &script0dialogs, numscript0dialogs,
+ PU_STATIC);
+ Z_Free(script0ptr); // haleyjd: free the original lump
+ }
+}
+
+//
+// P_PlayerHasItem
+//
+// [STRIFE] New function
+// haleyjd 09/02/10: Checks for inventory items, quest flags, etc. for dialogs.
+// Returns the amount possessed, or 0 if none.
+//
+int P_PlayerHasItem(player_t *player, mobjtype_t type)
+{
+ int i;
+
+ if(type > 0)
+ {
+ // check keys
+ if(type >= MT_KEY_BASE && type < MT_INV_SHADOWARMOR)
+ return (player->cards[type - MT_KEY_BASE]);
+
+ // check sigil pieces
+ if(type >= MT_SIGIL_A && type <= MT_SIGIL_E)
+ return (type - MT_SIGIL_A <= player->sigiltype);
+
+ // check quest tokens
+ if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
+ return (player->questflags & (1 << (type - MT_TOKEN_QUEST1)));
+
+ // check inventory
+ for(i = 0; i < 32; i++)
+ {
+ if(type == player->inventory[i].type)
+ return player->inventory[i].amount;
+ }
+ }
+ return 0;
+}
+
+//
+// P_DialogFind
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Looks for a dialog definition matching the given
+// Script ID # for an mobj.
+//
+mapdialog_t *P_DialogFind(mobjtype_t type, int jumptoconv)
+{
+ int i;
+
+ // check the map-specific dialogs first
+ for(i = 0; i < numleveldialogs; i++)
+ {
+ if(type == leveldialogs[i].speakerid)
+ {
+ if(jumptoconv <= 1)
+ return &leveldialogs[i];
+ else
+ --jumptoconv;
+ }
+ }
+
+ // check SCRIPT00 dialogs next
+ for(i = 0; i < numscript0dialogs; i++)
+ {
+ if(type == script0dialogs[i].speakerid)
+ return &script0dialogs[i];
+ }
+
+ // the default dialog is script 0 in the SCRIPT00 lump.
+ return &script0dialogs[0];
+}
+
+//
+// P_DialogGetStates
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Find the set of special dialog states (greetings, yes, no)
+// for a particular thing type.
+//
+static dialogstateset_t *P_DialogGetStates(mobjtype_t type)
+{
+ int i;
+
+ // look for a match by type
+ for(i = 0; i < numdialogstatesets; i++)
+ {
+ if(type == dialogstatesets[i].type)
+ return &dialogstatesets[i];
+ }
+
+ // return the default 0 record if no match.
+ return &dialogstatesets[0];
+}
+
+//
+// P_DialogGetMsg
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Redirects dialog messages when the script indicates that
+// the actor should use a random message stored in the executable instead.
+//
+static const char *P_DialogGetMsg(const char *message)
+{
+ // if the message starts with "RANDOM"...
+ if(!strncasecmp(message, DEH_String("RANDOM"), 6))
+ {
+ int i;
+ const char *nameloc = message + 7;
+
+ // look for a match in rndMessages for the string starting
+ // 7 chars after "RANDOM_"
+ for(i = 0; i < numrndmessages; i++)
+ {
+ if(!strncasecmp(nameloc, rndMessages[i].type_name, 4))
+ {
+ // found a match, so return a random message
+ int rnd = M_Random();
+ int nummessages = rndMessages[i].nummessages;
+ return DEH_String(rndMessages[i].messages[rnd % nummessages]);
+ }
+ }
+ }
+
+ // otherwise, just return the message passed in.
+ return message;
+}
+
+//
+// P_GiveInventoryItem
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Give an inventory item to the player, if possible.
+// villsa 09/09/10: Fleshed out routine
+//
+boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type)
+{
+ int curinv = 0;
+ int i;
+ boolean ok = false;
+ mobjtype_t item = 0;
+ inventory_t* invtail;
+
+ // repaint the status bar due to inventory changing
+ player->st_update = true;
+
+ while(1)
+ {
+ // inventory is full
+ if(curinv > player->numinventory)
+ return true;
+
+ item = player->inventory[curinv].type;
+ if(type < item)
+ {
+ if(curinv != MAXINVENTORYSLOTS)
+ {
+ // villsa - sort inventory item if needed
+ invtail = &player->inventory[player->numinventory - 1];
+ if(player->numinventory >= (curinv + 1))
+ {
+ for(i = player->numinventory; i >= (curinv + 1); --i)
+ {
+ invtail[1].sprite = invtail[0].sprite;
+ invtail[1].type = invtail[0].type;
+ invtail[1].amount = invtail[0].amount;
+
+ invtail--;
+ }
+ }
+
+ // villsa - add inventory item
+ player->inventory[curinv].amount = 1;
+ player->inventory[curinv].sprite = sprnum;
+ player->inventory[curinv].type = type;
+
+ // sort cursor if needed
+ if(player->numinventory)
+ {
+ if(curinv <= player->inventorycursor)
+ player->inventorycursor++;
+ }
+
+ player->numinventory++;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ if(type == item)
+ break;
+
+ curinv++;
+ }
+
+ // check amount of inventory item by using the mass from mobjinfo
+ if(player->inventory[curinv].amount < mobjinfo[item].mass)
+ {
+ player->inventory[curinv].amount++;
+ ok = true;
+ }
+ else
+ ok = false;
+
+ return ok;
+}
+
+//
+// P_GiveItemToPlayer
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Sorts out how to give something to the player.
+// Not strictly just for inventory items.
+// villsa 09/09/10: Fleshed out function
+//
+boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type)
+{
+ int i = 0;
+ line_t junk;
+ int sound = sfx_itemup; // haleyjd 09/21/10: different sounds for items
+
+ // set quest if mf_givequest flag is set
+ if(mobjinfo[type].flags & MF_GIVEQUEST)
+ player->questflags |= 1 << (mobjinfo[type].speed - 1);
+
+ // check for keys
+ if(type >= MT_KEY_BASE && type <= MT_NEWKEY5)
+ {
+ P_GiveCard(player, type - MT_KEY_BASE);
+ return true;
+ }
+
+ // check for quest tokens
+ if(type >= MT_TOKEN_QUEST1 && type <= MT_TOKEN_QUEST31)
+ {
+ if(mobjinfo[type].name)
+ {
+ strncpy(pickupstring, DEH_String(mobjinfo[type].name), 39);
+ player->message = pickupstring;
+ }
+ player->questflags |= 1 << (type - MT_TOKEN_QUEST1);
+
+ if(player == &players[consoleplayer])
+ S_StartSound(NULL, sound);
+ return true;
+ }
+
+ // haleyjd 09/22/10: Refactored to give sprites higher priority than
+ // mobjtypes and to implement missing logic.
+ switch(sprnum)
+ {
+ case SPR_HELT: // This is given only by the "DONNYTRUMP" cheat (aka Midas)
+ P_GiveInventoryItem(player, SPR_HELT, MT_TOKEN_TOUGHNESS);
+ P_GiveInventoryItem(player, SPR_GUNT, MT_TOKEN_ACCURACY);
+
+ // [STRIFE] Bizarre...
+ for(i = 0; i < 5 * player->accuracy + 300; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case SPR_ARM1: // Armor 1
+ if(!P_GiveArmor(player, -2))
+ P_GiveInventoryItem(player, sprnum, type);
+ break;
+
+ case SPR_ARM2: // Armor 2
+ if(!P_GiveArmor(player, -1))
+ P_GiveInventoryItem(player, sprnum, type);
+ break;
+
+ case SPR_COIN: // 1 Gold
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case SPR_CRED: // 10 Gold
+ for(i = 0; i < 10; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case SPR_SACK: // 25 gold
+ for(i = 0; i < 25; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case SPR_CHST: // 50 gold
+ for(i = 0; i < 50; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+
+ case SPR_BBOX: // Box of Bullets
+ if(!P_GiveAmmo(player, am_bullets, 5))
+ return false;
+ break;
+
+ case SPR_BLIT: // Bullet Clip
+ if(!P_GiveAmmo(player, am_bullets, 1))
+ return false;
+ break;
+
+ case SPR_PMAP: // Map powerup
+ if(!P_GivePower(player, pw_allmap))
+ return false;
+ sound = sfx_yeah; // bluh-doop!
+ break;
+
+ case SPR_COMM: // Communicator
+ if(!P_GivePower(player, pw_communicator))
+ return false;
+ sound = sfx_yeah; // bluh-doop!
+ break;
+
+ case SPR_MSSL: // Mini-missile
+ if(!P_GiveAmmo(player, am_missiles, 1))
+ return false;
+ break;
+
+ case SPR_ROKT: // Crate of missiles
+ if(!P_GiveAmmo(player, am_missiles, 5))
+ return false;
+ break;
+
+ case SPR_BRY1: // Battery cell
+ if(!P_GiveAmmo(player, am_cell, 1))
+ return false;
+ break;
+
+ case SPR_CPAC: // Cell pack
+ if(!P_GiveAmmo(player, am_cell, 5))
+ return false;
+ break;
+
+ case SPR_PQRL: // Poison bolts
+ if(!P_GiveAmmo(player, am_poisonbolts, 5))
+ return false;
+ break;
+
+ case SPR_XQRL: // Electric bolts
+ if(!P_GiveAmmo(player, am_elecbolts, 5))
+ return false;
+ break;
+
+ case SPR_GRN1: // HE Grenades
+ if(!P_GiveAmmo(player, am_hegrenades, 1))
+ return false;
+ break;
+
+ case SPR_GRN2: // WP Grenades
+ if(!P_GiveAmmo(player, am_wpgrenades, 1))
+ return false;
+ break;
+
+ case SPR_BKPK: // Backpack (aka Ammo Satchel)
+ 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);
+ break;
+
+ case SPR_RIFL: // Assault Rifle
+ if(player->weaponowned[wp_rifle])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_rifle, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_FLAM: // Flamethrower
+ if(player->weaponowned[wp_flame])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_flame, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_MMSL: // Mini-missile Launcher
+ if(player->weaponowned[wp_missile])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_missile, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_TRPD: // Mauler
+ if(player->weaponowned[wp_mauler])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_mauler, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_CBOW: // Here's a crossbow. Just aim straight, and *SPLAT!*
+ if(player->weaponowned[wp_elecbow])
+ return false;
+
+ if(!P_GiveWeapon(player, wp_elecbow, false))
+ return false;
+
+ sound = sfx_wpnup; // SHK-CHK!
+ break;
+
+ case SPR_TOKN: // Miscellaneous items - These are determined by thingtype.
+ switch(type)
+ {
+ case MT_KEY_HAND: // Severed hand
+ P_GiveCard(player, key_SeveredHand);
+ break;
+
+ case MT_MONY_300: // 300 Gold (this is the only way to get it, in fact)
+ for(i = 0; i < 300; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ case MT_TOKEN_AMMO: // Ammo token - you get this from the Weapons Trainer
+ if(player->ammo[am_bullets] >= 50)
+ return false;
+
+ player->ammo[am_bullets] = 50;
+ break;
+
+ case MT_TOKEN_HEALTH: // Health token - from the Front's doctor
+ if(!P_GiveBody(player, healthamounts[gameskill]))
+ return false;
+ break;
+
+ case MT_TOKEN_ALARM: // Alarm token - particularly from the Oracle.
+ P_NoiseAlert(player->mo, player->mo);
+ A_AlertSpectreC(dialogtalker); // BUG: assumes in a dialog o_O
+ break;
+
+ case MT_TOKEN_DOOR1: // Door special 1
+ junk.tag = 222;
+ EV_DoDoor(&junk, open);
+ break;
+
+ case MT_TOKEN_PRISON_PASS: // Door special 1 - Prison pass
+ junk.tag = 223;
+ EV_DoDoor(&junk, open);
+ if(gamemap == 2) // If on Tarnhill, give Prison pass object
+ P_GiveInventoryItem(player, sprnum, type);
+ break;
+
+ case MT_TOKEN_SHOPCLOSE: // Door special 3 - "Shop close" - unused?
+ junk.tag = 222;
+ EV_DoDoor(&junk, close);
+ break;
+
+ case MT_TOKEN_DOOR3: // Door special 4 (or 3? :P )
+ junk.tag = 224;
+ EV_DoDoor(&junk, close);
+ break;
+
+ case MT_TOKEN_STAMINA: // Stamina upgrade
+ if(player->stamina >= 100)
+ return false;
+
+ player->stamina += 10;
+ P_GiveBody(player, 200); // full healing
+ break;
+
+ case MT_TOKEN_NEW_ACCURACY: // Accuracy upgrade
+ if(player->accuracy >= 100)
+ return false;
+
+ player->accuracy += 10;
+ break;
+
+ case MT_SLIDESHOW: // Slideshow (start a finale)
+ gameaction = ga_victory;
+ if(gamemap == 10)
+ P_GiveItemToPlayer(player, SPR_TOKN, MT_TOKEN_QUEST17);
+ break;
+
+ default: // The default is to just give it as an inventory item.
+ P_GiveInventoryItem(player, sprnum, type);
+ break;
+ }
+ break;
+
+ default: // The ultimate default: Give it as an inventory item.
+ if(!P_GiveInventoryItem(player, sprnum, type))
+ return false;
+ break;
+ }
+
+ // Play sound.
+ if(player == &players[consoleplayer])
+ S_StartSound(NULL, sound);
+
+ return true;
+}
+
+//
+// P_TakeDialogItem
+//
+// [STRIFE] New function
+// haleyjd 09/03/10: Removes needed items from the player's inventory.
+//
+static void P_TakeDialogItem(player_t *player, int type, int amount)
+{
+ int i;
+
+ if(amount <= 0)
+ return;
+
+ for(i = 0; i < player->numinventory; i++)
+ {
+ // find a matching item
+ if(type != player->inventory[i].type)
+ continue;
+
+ // if there is none left...
+ if((player->inventory[i].amount -= amount) < 1)
+ {
+ // ...shift everything above it down
+ int j;
+
+ // BUG: They should have stopped at j < numinventory. This
+ // seems to implicitly assume that numinventory is always at
+ // least one less than the max # of slots, otherwise it
+ // pulls in data from the following player_t fields:
+ // st_update, numinventory, inventorycursor, accuracy, stamina
+ for(j = i + 1; j <= player->numinventory; j++)
+ {
+ inventory_t *item1 = &(player->inventory[j - 1]);
+ inventory_t *item2 = &(player->inventory[j]);
+
+ *item1 = *item2;
+ }
+
+ // blank the topmost slot
+ // BUG: This will overwrite the aforementioned fields if
+ // numinventory is equal to the number of slots!
+ // STRIFE-TODO: Overflow emulation?
+ player->inventory[player->numinventory].type = NUMMOBJTYPES;
+ player->inventory[player->numinventory].sprite = -1;
+ player->numinventory--;
+
+ // update cursor position
+ if(player->inventorycursor >= player->numinventory)
+ {
+ if(player->inventorycursor)
+ player->inventorycursor--;
+ }
+ } // end if
+
+ return; // done!
+
+ } // end for
+}
+
+//
+// P_DialogDrawer
+//
+// This function is set as the drawer callback for the dialog menu.
+//
+static void P_DialogDrawer(void)
+{
+ angle_t angle;
+ int y;
+ int i;
+ int height;
+ int finaly;
+ char choicetext[64];
+ char choicetext2[64];
+
+ // Run down bonuscount faster than usual so that flashes from being given
+ // items are less obvious.
+ if(dialogplayer->bonuscount)
+ {
+ dialogplayer->bonuscount -= 3;
+ if(dialogplayer->bonuscount < 0)
+ dialogplayer->bonuscount = 0;
+ }
+
+ angle = R_PointToAngle2(dialogplayer->mo->x,
+ dialogplayer->mo->y,
+ dialogtalker->x,
+ dialogtalker->y);
+ angle -= dialogplayer->mo->angle;
+
+ // Dismiss the dialog if the player is out of alignment, or the thing he was
+ // talking to is now engaged in battle.
+ if ((angle > ANG45 && angle < (ANG270+ANG45))
+ || (dialogtalker->flags & MF_NODIALOG) != 0)
+ {
+ P_DialogDoChoice(dialogmenu.numitems - 1);
+ }
+
+ dialogtalker->reactiontime = 2;
+
+ // draw background
+ if(dialogbgpiclumpnum != -1)
+ {
+ patch_t *patch = W_CacheLumpNum(dialogbgpiclumpnum, PU_CACHE);
+ V_DrawPatchDirect(0, 0, patch);
+ }
+
+ // if there's a valid background pic, delay drawing the rest of the menu
+ // for a while; otherwise, it will appear immediately
+ if(dialogbgpiclumpnum == -1 || menupausetime <= gametic)
+ {
+ if(menuindialog)
+ {
+ // time to pause the game?
+ if(menupausetime + 3 < gametic)
+ menupause = true;
+ }
+
+ // draw character name
+ M_WriteText(12, 18, dialogname);
+ y = 28;
+
+ // show text (optional for dialogs with voices)
+ if(dialogshowtext || currentdialog->voice[0] == '\0')
+ y = M_WriteText(20, 28, dialogtext);
+
+ height = 20 * dialogmenu.numitems;
+
+ finaly = 175 - height; // preferred height
+ if(y > finaly)
+ finaly = 199 - height; // height it will bump down to if necessary.
+
+ // draw divider
+ M_WriteText(42, finaly - 6, DEH_String("______________________________"));
+
+ dialogmenu.y = finaly + 6;
+ y = 0;
+
+ // draw the menu items
+ for(i = 0; i < dialogmenu.numitems - 1; i++)
+ {
+ DEH_snprintf(choicetext, sizeof(choicetext),
+ "%d) %s", i + 1, currentdialog->choices[i].text);
+
+ // alternate text for items that need money
+ if(currentdialog->choices[i].needamounts[0] > 0)
+ {
+ // haleyjd 20120401: necessary to avoid undefined behavior:
+ strcpy(choicetext2, choicetext);
+ DEH_snprintf(choicetext, sizeof(choicetext),
+ "%s for %d",
+ choicetext2,
+ currentdialog->choices[i].needamounts[0]);
+ }
+
+ M_WriteText(dialogmenu.x, dialogmenu.y + 3 + y, choicetext);
+ y += 19;
+ }
+
+ // draw the final item for dismissing the dialog
+ M_WriteText(dialogmenu.x, 19 * i + dialogmenu.y + 3, dialoglastmsgbuffer);
+ }
+}
+
+//
+// P_DialogDoChoice
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Handles making a choice in a dialog. Installed as the
+// callback for all items in the dialogmenu structure.
+//
+void P_DialogDoChoice(int choice)
+{
+ int i = 0, nextdialog = 0;
+ boolean candochoice = true;
+ char *message = NULL;
+ mapdlgchoice_t *currentchoice;
+
+ if(choice == -1)
+ choice = dialogmenu.numitems - 1;
+
+ currentchoice = &(currentdialog->choices[choice]);
+
+ I_StartVoice(NULL); // STRIFE-TODO: verify (should stop previous voice I believe)
+
+ // villsa 09/08/10: converted into for loop
+ for(i = 0; i < MDLG_MAXITEMS; i++)
+ {
+ if(P_PlayerHasItem(dialogplayer, currentchoice->needitems[i]) <
+ currentchoice->needamounts[i])
+ {
+ candochoice = false; // nope, missing something
+ }
+ }
+
+ if(choice != dialogmenu.numitems - 1 && candochoice)
+ {
+ int item;
+
+ message = currentchoice->textok;
+ if(dialogtalkerstates->yes)
+ P_SetMobjState(dialogtalker, dialogtalkerstates->yes);
+
+ item = currentchoice->giveitem;
+ if(item < 0 ||
+ P_GiveItemToPlayer(dialogplayer,
+ states[mobjinfo[item].spawnstate].sprite,
+ item))
+ {
+ // if successful, take needed items
+ int count = 0;
+ // villsa 09/08/10: converted into for loop
+ for(count = 0; count < MDLG_MAXITEMS; count++)
+ {
+ P_TakeDialogItem(dialogplayer,
+ currentchoice->needitems[count],
+ currentchoice->needamounts[count]);
+ }
+ }
+ else
+ message = DEH_String("You seem to have enough!");
+
+ // store next dialog into the talking actor
+ nextdialog = currentchoice->next;
+ if(nextdialog != 0)
+ dialogtalker->miscdata = (byte)(abs(nextdialog));
+ }
+ else
+ {
+ // not successful
+ message = currentchoice->textno;
+ if(dialogtalkerstates->no)
+ P_SetMobjState(dialogtalker, dialogtalkerstates->no);
+ }
+
+ if(choice != dialogmenu.numitems - 1)
+ {
+ int objective;
+ char *objlump;
+
+ if((objective = currentchoice->objective))
+ {
+ DEH_snprintf(mission_objective, OBJECTIVE_LEN, "log%i", objective);
+ objlump = W_CacheLumpName(mission_objective, PU_CACHE);
+ strncpy(mission_objective, objlump, OBJECTIVE_LEN);
+ }
+ // haleyjd 20130301: v1.31 hack: if first char of message is a period,
+ // clear the player's message. Is this actually used anywhere?
+ if(gameversion == exe_strife_1_31 && message[0] == '.')
+ message = NULL;
+ dialogplayer->message = message;
+ }
+
+ dialogtalker->angle = dialogtalkerangle;
+ dialogplayer->st_update = true;
+ M_ClearMenus(0);
+
+ if(nextdialog >= 0 || gameaction == ga_victory) // Macil hack
+ menuindialog = false;
+ else
+ P_DialogStart(dialogplayer);
+}
+
+//
+// P_DialogStartP1
+//
+// [STRIFE] New function
+// haleyjd 09/13/10: This is a hack used by the finale system.
+//
+void P_DialogStartP1(void)
+{
+ P_DialogStart(&players[0]);
+}
+
+//
+// P_DialogStart
+//
+// villsa [STRIFE] New function
+//
+void P_DialogStart(player_t *player)
+{
+ int i = 0;
+ int pic;
+ int rnd = 0;
+ char* byetext;
+ int jumptoconv;
+
+ if(menuactive || netgame)
+ return;
+
+ // are we facing towards our NPC?
+ P_AimLineAttack(player->mo, player->mo->angle, (128*FRACUNIT));
+ if(!linetarget)
+ {
+ P_AimLineAttack(player->mo, player->mo->angle + (ANG90/16), (128*FRACUNIT));
+ if(!linetarget)
+ P_AimLineAttack(player->mo, player->mo->angle - (ANG90/16), (128*FRACUNIT));
+ }
+
+ if(!linetarget)
+ return;
+
+ // already in combat, can't talk to it
+ if(linetarget->flags & MF_NODIALOG)
+ return;
+
+ // set pointer to the character talking
+ dialogtalker = linetarget;
+
+ // play a sound
+ if(player == &players[consoleplayer])
+ S_StartSound(0, sfx_radio);
+
+ linetarget->target = player->mo; // target the player
+ dialogtalker->reactiontime = 2; // set reactiontime
+ dialogtalkerangle = dialogtalker->angle; // remember original angle
+
+ // face talker towards player
+ A_FaceTarget(dialogtalker);
+
+ // face towards NPC's direction
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y,
+ dialogtalker->x,
+ dialogtalker->y);
+ // set pointer to player talking
+ dialogplayer = player;
+
+ // haleyjd 09/08/10: get any stored dialog state from this object
+ jumptoconv = linetarget->miscdata;
+
+ // check item requirements
+ while(1)
+ {
+ int i = 0;
+ currentdialog = P_DialogFind(linetarget->type, jumptoconv);
+
+ // dialog's jumptoconv equal to 0? There's nothing to jump to.
+ if(currentdialog->jumptoconv == 0)
+ break;
+
+ // villsa 09/08/10: converted into for loop
+ for(i = 0; i < MDLG_MAXITEMS; i++)
+ {
+ // if the item is non-zero, the player must have at least one in his
+ // or her inventory
+ if(currentdialog->checkitem[i] != 0 &&
+ P_PlayerHasItem(dialogplayer, currentdialog->checkitem[i]) < 1)
+ break;
+ }
+
+ if(i < MDLG_MAXITEMS) // didn't find them all? this is our dialog!
+ break;
+
+ jumptoconv = currentdialog->jumptoconv;
+ }
+
+ M_DialogDimMsg(20, 28, currentdialog->text, false);
+ dialogtext = P_DialogGetMsg(currentdialog->text);
+
+ // get states
+ dialogtalkerstates = P_DialogGetStates(linetarget->type);
+
+ // have talker greet the player
+ if(dialogtalkerstates->greet)
+ P_SetMobjState(dialogtalker, dialogtalkerstates->greet);
+
+ // get talker's name
+ if(currentdialog->name[0])
+ dialogname = currentdialog->name;
+ else
+ {
+ // use a fallback:
+ if(mobjinfo[linetarget->type].name)
+ dialogname = DEH_String(mobjinfo[linetarget->type].name); // mobjtype name
+ else
+ dialogname = DEH_String("Person"); // default name - like Joe in Doom 3 :P
+ }
+
+ // setup number of choices to choose from
+ for(i = 0; i < MDLG_MAXCHOICES; i++)
+ {
+ if(!currentdialog->choices[i].giveitem)
+ break;
+ }
+
+ // set number of choices to menu
+ dialogmenu.numitems = i + 1;
+
+ rnd = M_Random() % 3;
+
+ // setup dialog menu
+ M_StartControlPanel();
+ menupause = false;
+ menuindialog = true;
+ menupausetime = gametic + 17;
+ currentMenu = &dialogmenu;
+
+ if(i >= dialogmenu.lastOn)
+ itemOn = dialogmenu.lastOn;
+ else
+ itemOn = 0;
+
+ // get backdrop
+ pic = W_CheckNumForName(currentdialog->backpic);
+ dialogbgpiclumpnum = pic;
+ if(pic != -1)
+ V_DrawPatchDirect(0, 0, W_CacheLumpNum(pic, PU_CACHE));
+
+ // get voice
+ I_StartVoice(currentdialog->voice);
+
+ // get bye text
+ switch(rnd)
+ {
+ case 2:
+ byetext = DEH_String("BYE!");
+ break;
+ case 1:
+ byetext = DEH_String("Thanks, Bye!");
+ break;
+ default:
+ case 0:
+ byetext = DEH_String("See you later!");
+ break;
+ }
+
+ DEH_snprintf(dialoglastmsgbuffer, sizeof(dialoglastmsgbuffer),
+ "%d) %s", i + 1, byetext);
+}
+
+// EOF
+
+
diff --git a/src/strife/p_dialog.h b/src/strife/p_dialog.h
new file mode 100644
index 00000000..7463490b
--- /dev/null
+++ b/src/strife/p_dialog.h
@@ -0,0 +1,108 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1996 Rogue Entertainment / Velocity, Inc.
+// Copyright(C) 2010 James Haley, Samuel Villareal
+//
+// 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:
+//
+// [STRIFE] New Module
+//
+// Dialog Engine for Strife
+//
+//-----------------------------------------------------------------------------
+
+#ifndef P_DIALOG_H__
+#define P_DIALOG_H__
+
+#define OBJECTIVE_LEN 300
+
+#define MAXINVENTORYSLOTS 30
+
+#define MDLG_CHOICELEN 32
+#define MDLG_MSGLEN 80
+#define MDLG_NAMELEN 16
+#define MDLG_LUMPLEN 8
+#define MDLG_TEXTLEN 320
+#define MDLG_MAXCHOICES 5
+#define MDLG_MAXITEMS 3
+
+extern char mission_objective[OBJECTIVE_LEN];
+
+extern int dialogshowtext;
+
+// villsa - convenient macro for giving objective logs to player
+#define GiveObjective(x, minlumpnum) \
+do { \
+ int obj_ln = W_CheckNumForName(DEH_String(x)); \
+ if(obj_ln > minlumpnum) \
+ strncpy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), OBJECTIVE_LEN);\
+} while(0)
+
+// haleyjd - voice and objective in one
+#define GiveVoiceObjective(voice, log, minlumpnum) \
+do { \
+ int obj_ln = W_CheckNumForName(DEH_String(log)); \
+ I_StartVoice(DEH_String(voice)); \
+ if(obj_ln > minlumpnum) \
+ strncpy(mission_objective, W_CacheLumpNum(obj_ln, PU_CACHE), OBJECTIVE_LEN);\
+} while(0)
+
+typedef struct mapdlgchoice_s
+{
+ int giveitem; // item given when successful
+ int needitems[MDLG_MAXITEMS]; // item needed for success
+ int needamounts[MDLG_MAXITEMS]; // amount of items needed
+ char text[MDLG_CHOICELEN]; // normal text
+ char textok[MDLG_MSGLEN]; // message given on success
+ int next; // next dialog?
+ int objective; // ???
+ char textno[MDLG_MSGLEN]; // message given on failure
+} mapdlgchoice_t;
+
+typedef struct mapdialog_s
+{
+ int speakerid; // script ID# for mobjtype that will use this dialog
+ int dropitem; // item to drop if that thingtype is killed
+ int checkitem[MDLG_MAXITEMS]; // item(s) needed to see this dialog
+ int jumptoconv; // conversation to jump to when... ?
+ char name[MDLG_NAMELEN]; // name of speaker
+ char voice[MDLG_LUMPLEN]; // voice file to play
+ char backpic[MDLG_LUMPLEN]; // backdrop pic for character, if any
+ char text[MDLG_TEXTLEN]; // main message text
+
+ // options that this dialog gives the player
+ mapdlgchoice_t choices[MDLG_MAXCHOICES];
+} mapdialog_t;
+
+void P_DialogLoad(void);
+void P_DialogStart(player_t *player);
+void P_DialogDoChoice(int choice);
+boolean P_GiveItemToPlayer(player_t *player, int sprnum, mobjtype_t type);
+boolean P_GiveInventoryItem(player_t *player, int sprnum, mobjtype_t type);
+boolean P_UseInventoryItem(player_t* player, int item);
+void P_DialogStartP1(void);
+mapdialog_t* P_DialogFind(mobjtype_t type, int jumptoconv);
+int P_PlayerHasItem(player_t *player, mobjtype_t type);
+
+#endif
+
+// EOF
+
+
diff --git a/src/strife/p_doors.c b/src/strife/p_doors.c
new file mode 100644
index 00000000..e85d9d7d
--- /dev/null
+++ b/src/strife/p_doors.c
@@ -0,0 +1,1378 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 "z_zone.h"
+#include "doomdef.h"
+#include "deh_main.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "dstrings.h"
+#include "sounds.h"
+
+// [STRIFE]
+#include "p_dialog.h"
+#include "i_system.h"
+
+
+//
+// VERTICAL DOORS
+//
+
+//
+// T_VerticalDoor
+//
+void T_VerticalDoor(vldoor_t* door)
+{
+ result_e res1;
+ result_e res2;
+
+ switch(door->direction)
+ {
+ case 0:
+ // WAITING
+ if (!--door->topcountdown)
+ {
+ switch(door->type)
+ {
+ case blazeRaise:
+ door->direction = -1; // time to go back down
+ S_StartSound(&door->sector->soundorg, sfx_bdcls);
+ break;
+
+ case normal:
+ door->direction = -1; // time to go back down
+ // villsa [STRIFE] closesound added
+ S_StartSound(&door->sector->soundorg, door->closesound);
+ break;
+
+ // villsa [STRIFE]
+ case shopClose:
+ door->direction = 1;
+ door->speed = (2*FRACUNIT);
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ case close30ThenOpen:
+ door->direction = 1;
+
+ // villsa [STRIFE] opensound added
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 2:
+ // INITIAL WAIT
+ if (!--door->topcountdown)
+ {
+ switch(door->type)
+ {
+ case raiseIn5Mins:
+ door->direction = 1;
+ door->type = normal;
+
+ // villsa [STRIFE] opensound added
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ // villsa [STRIFE]
+ case -2:
+ // SPLIT
+ res1 = T_MovePlane(door->sector, door->speed, door->topheight, 0, 1, 1);
+ res2 = T_MovePlane(door->sector, door->speed, door->topwait, 0, 0, -1);
+
+ if(res1 == pastdest && res2 == pastdest)
+ {
+ door->sector->specialdata = NULL;
+ P_RemoveThinker(&door->thinker); // unlink and free
+ }
+
+ break;
+
+ case -1:
+ // DOWN
+ res1 = T_MovePlane(door->sector, door->speed, door->sector->floorheight, false, 1, door->direction);
+ if(res1 == pastdest)
+ {
+ switch(door->type)
+ {
+ case normal:
+ case close:
+ case blazeRaise:
+ case blazeClose:
+ door->sector->specialdata = NULL;
+ P_RemoveThinker (&door->thinker); // unlink and free
+ // villsa [STRIFE] no sounds
+ break;
+
+ case close30ThenOpen:
+ door->direction = 0;
+ door->topcountdown = TICRATE*30;
+ break;
+
+ // villsa [STRIFE]
+ case shopClose:
+ door->direction = 0;
+ door->topcountdown = TICRATE*120;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else if(res1 == crushed)
+ {
+ switch(door->type)
+ {
+ case blazeClose:
+ case close: // DO NOT GO BACK UP!
+ case shopClose: // villsa [STRIFE]
+ break;
+
+ default:
+ door->direction = 1;
+ // villsa [STRIFE] opensound added
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+ }
+ }
+ break;
+
+ case 1:
+ // UP
+ res1 = T_MovePlane(door->sector,
+ door->speed,
+ door->topheight,
+ false,1,door->direction);
+
+ if(res1 == pastdest)
+ {
+ switch(door->type)
+ {
+ case blazeRaise:
+ case normal:
+ door->direction = 0; // wait at top
+ door->topcountdown = door->topwait;
+ break;
+
+ case close30ThenOpen:
+ case blazeOpen:
+ case open:
+ case shopClose: // villsa [STRIFE]
+ door->sector->specialdata = NULL;
+ P_RemoveThinker (&door->thinker); // unlink and free
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+ }
+}
+
+
+//
+// EV_DoLockedDoor
+// Move a locked door up/down
+//
+// [STRIFE] This game has a crap load of keys. And this function doesn't even
+// deal with all of them...
+//
+int EV_DoLockedDoor(line_t* line, vldoor_e type, mobj_t* thing)
+{
+ player_t* p;
+
+ p = thing->player;
+
+ if(!p)
+ return 0;
+
+ switch(line->special)
+ {
+ case 99:
+ case 133:
+ if(!p->cards[key_IDCard])
+ {
+ p->message = DEH_String("You need an id card");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 134:
+ case 135:
+ if(!p->cards[key_IDBadge])
+ {
+ p->message = DEH_String("You need an id badge");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 136:
+ case 137:
+ if(!p->cards[key_Passcard])
+ {
+ p->message = DEH_String("You need a pass card");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 151:
+ case 164:
+ if(!p->cards[key_GoldKey])
+ {
+ p->message = DEH_String("You need a gold key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 153:
+ case 163:
+ if(!p->cards[key_SilverKey])
+ {
+ p->message = DEH_String("You need a silver key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 152:
+ case 162:
+ if(!p->cards[key_BrassKey])
+ {
+ p->message = DEH_String("You need a brass key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 167:
+ case 168:
+ if(!p->cards[key_SeveredHand])
+ {
+ p->message = DEH_String("Hand print not on file");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 171:
+ if(!p->cards[key_PrisonKey])
+ {
+ p->message = DEH_String("You don't have the key to the prison");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 172:
+ if(!p->cards[key_Power1Key])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 173:
+ if(!p->cards[key_Power2Key])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 176:
+ if(!p->cards[key_Power3Key])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 189:
+ if(!p->cards[key_OracleKey])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 191:
+ if(!p->cards[key_MilitaryID])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 192:
+ if(!p->cards[key_WarehouseKey])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+
+ case 223:
+ if(!p->cards[key_MineKey])
+ {
+ p->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return 0;
+ }
+ break;
+ }
+
+ return EV_DoDoor(line,type);
+}
+
+
+//
+// EV_DoDoor
+//
+
+int EV_DoDoor(line_t* line, vldoor_e type)
+{
+ int secnum, rtn;
+ sector_t* sec;
+ vldoor_t* door;
+
+ secnum = -1;
+ rtn = 0;
+
+ while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if(sec->specialdata)
+ continue;
+
+
+ // new door thinker
+ rtn = 1;
+ door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
+ P_AddThinker (&door->thinker);
+ sec->specialdata = door;
+
+ door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
+ door->sector = sec;
+ door->type = type;
+ door->topwait = VDOORWAIT;
+ door->speed = VDOORSPEED;
+ R_SoundNumForDoor(door); // villsa [STRIFE] set door sounds
+
+ switch(type)
+ {
+ // villsa [STRIFE] new door type
+ case splitOpen:
+ door->direction = -2;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->speed = FRACUNIT;
+ // yes, it using topwait to get the floor height
+ door->topwait = P_FindLowestFloorSurrounding(sec);
+ if(door->topheight == sec->ceilingheight)
+ continue;
+
+ S_StartSound(&sec->soundorg, door->opensound);
+ break;
+
+ // villsa [STRIFE] new door type
+ case splitRaiseNearest:
+ door->direction = -2;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->speed = FRACUNIT;
+ // yes, it using topwait to get the floor height
+ door->topwait = P_FindHighestFloorSurrounding(sec);
+ if(door->topheight == sec->ceilingheight)
+ continue;
+
+ S_StartSound(&sec->soundorg, door->opensound);
+ break;
+
+ case blazeClose:
+ case shopClose: // villsa [STRIFE]
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->direction = -1;
+ door->speed = VDOORSPEED * 4;
+ S_StartSound(&door->sector->soundorg, sfx_bdcls);
+ break;
+
+ case close:
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+ door->direction = -1;
+
+ // villsa [STRIFE] set door sounds
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ case close30ThenOpen:
+ door->topheight = sec->ceilingheight;
+ door->direction = -1;
+
+ // villsa [STRIFE] set door sounds
+ S_StartSound(&door->sector->soundorg, door->closesound);
+ 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(&door->sector->soundorg, sfx_bdopn);
+ break;
+
+ case normal:
+ case open:
+ door->direction = 1;
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+
+ if(door->topheight != sec->ceilingheight)
+ S_StartSound(&door->sector->soundorg, door->opensound);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ return rtn;
+}
+
+//
+// EV_ClearForceFields
+//
+// villsa [STRIFE] new function
+//
+boolean EV_ClearForceFields(line_t* line)
+{
+ int secnum;
+ sector_t* sec;
+ int i;
+ line_t* secline;
+ boolean ret = false;
+
+ secnum = -1;
+
+ while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+
+ line->special = 0;
+ ret = true;
+
+ // haleyjd 09/18/10: fixed to continue w/linecount == 0, not return
+ for(i = 0; i < sec->linecount; i++)
+ {
+ secline = sec->lines[i];
+ if(!(secline->flags & ML_TWOSIDED))
+ continue;
+ if(secline->special != 148)
+ continue;
+
+ secline->flags &= ~ML_BLOCKING;
+ secline->special = 0;
+ sides[secline->sidenum[0]].midtexture = 0;
+ sides[secline->sidenum[1]].midtexture = 0;
+ }
+ }
+
+ return ret;
+}
+
+
+//
+// EV_VerticalDoor : open a door manually, no tag value
+//
+// [STRIFE] Tons of new door types were added.
+//
+void EV_VerticalDoor(line_t* line, mobj_t* thing)
+{
+ player_t* player;
+ sector_t* sec;
+ vldoor_t* door;
+ int side;
+
+ side = 0; // only front sides can be used
+
+ // Check for locks
+ player = thing->player;
+
+ // haleyjd 09/15/10: [STRIFE] myriad checks here...
+ switch(line->special)
+ {
+ case 26: // DR ID Card door
+ case 32: // D1 ID Card door
+ if(!player->cards[key_IDCard])
+ {
+ player->message = DEH_String("You need an id card to open this door");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 27: // DR Pass Card door
+ case 34: // D1 Pass Card door
+ if(!player->cards[key_Passcard])
+ {
+ player->message = DEH_String("You need a pass card key to open this door");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 28: // DR ID Badge door
+ case 33: // D1 ID Badge door
+ if(!player->cards[key_IDBadge])
+ {
+ player->message = DEH_String("You need an id badge to open this door");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 156: // D1 brass key door
+ case 161: // DR brass key door
+ if(!player->cards[key_BrassKey])
+ {
+ player->message = DEH_String("You need a brass key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 157: // D1 silver key door
+ case 160: // DR silver key door
+ if(!player->cards[key_SilverKey])
+ {
+ player->message = DEH_String("You need a silver key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 158: // D1 gold key door
+ case 159: // DR gold key door
+ if(!player->cards[key_GoldKey])
+ {
+ player->message = DEH_String("You need a gold key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ // villsa [STRIFE] added 09/15/10
+ case 165:
+ player->message = DEH_String("That doesn't seem to work");
+ S_StartSound(NULL, sfx_oof);
+ return;
+
+ case 166: // DR Hand Print door
+ if(!player->cards[key_SeveredHand])
+ {
+ player->message = DEH_String("Hand print not on file");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 169: // DR Base key door
+ if(!player->cards[key_BaseKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 170: // DR Gov's Key door
+ if(!player->cards[key_GovsKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 190: // DR Order Key door
+ if(!player->cards[key_OrderKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 205: // DR "Only in retail"
+ player->message = DEH_String("THIS AREA IS ONLY AVAILABLE IN THE "
+ "RETAIL VERSION OF STRIFE");
+ S_StartSound(NULL, sfx_oof);
+ return;
+
+ case 213: // DR Chalice door
+ if(!P_PlayerHasItem(player, MT_INV_CHALICE))
+ {
+ player->message = DEH_String("You need the chalice!");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 217: // DR Core Key door
+ if(!player->cards[key_CoreKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 221: // DR Mauler Key door
+ if(!player->cards[key_MaulerKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 224: // DR Chapel Key door
+ if(!player->cards[key_ChapelKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 225: // DR Catacomb Key door
+ if(!player->cards[key_CatacombKey])
+ {
+ player->message = DEH_String("You don't have the key");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ case 232: // DR Oracle Pass door
+ if(!(player->questflags & QF_QUEST18))
+ {
+ player->message = DEH_String("You need the Oracle Pass!");
+ S_StartSound(NULL, sfx_oof);
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // if the sector has an active thinker, use it
+ sec = sides[ line->sidenum[side^1]] .sector;
+
+ if (sec->specialdata)
+ {
+ door = sec->specialdata;
+ // [STRIFE] Adjusted to handle linetypes handled here by Strife.
+ // BUG: Not all door types are checked here. This means that certain
+ // door lines are allowed to fall through and start a new thinker on the
+ // sector! This is why some doors can become jammed in Strife - stuck in
+ // midair, or unable to be opened at all. Multiple thinkers will fight
+ // over how to move the door. They should have added a default return if
+ // they weren't going to handle this unconditionally...
+ switch(line->special)
+ {
+ case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s
+ case 26:
+ case 27:
+ case 28:
+ case 117:
+ case 159: // villsa
+ case 160: // haleyjd
+ case 161: // villsa
+ case 166: // villsa
+ case 169: // villsa
+ case 170: // villsa
+ case 190: // villsa
+ case 213: // villsa
+ case 232: // villsa
+ if(door->direction == -1)
+ door->direction = 1; // go back up
+ else
+ {
+ if (!thing->player)
+ return;
+
+ // When is a door not a door?
+ // In Vanilla, door->direction is set, even though
+ // "specialdata" might not actually point at a door.
+
+ if (door->thinker.function.acp1 == (actionf_p1) T_VerticalDoor)
+ {
+ door->direction = -1; // start going down immediately
+ }
+ else if (door->thinker.function.acp1 == (actionf_p1) T_PlatRaise)
+ {
+ // Erm, this is a plat, not a door.
+ // This notably causes a problem in ep1-0500.lmp where
+ // a plat and a door are cross-referenced; the door
+ // doesn't open on 64-bit.
+ // The direction field in vldoor_t corresponds to the wait
+ // field in plat_t. Let's set that to -1 instead.
+
+ plat_t *plat;
+
+ plat = (plat_t *) door;
+ plat->wait = -1;
+ }
+ else
+ {
+ // This isn't a door OR a plat. Now we're in trouble.
+
+ fprintf(stderr, "EV_VerticalDoor: Tried to close "
+ "something that wasn't a door.\n");
+
+ // Try closing it anyway. At least it will work on 32-bit
+ // machines.
+
+ door->direction = -1;
+ }
+ }
+ return;
+ default:
+ break;
+ }
+ }
+
+ // haleyjd 09/15/10: [STRIFE] Removed DOOM door sounds
+
+ // new door thinker
+ door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
+ P_AddThinker (&door->thinker);
+ sec->specialdata = door;
+ door->thinker.function.acp1 = (actionf_p1) T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 1;
+ door->speed = VDOORSPEED;
+ door->topwait = VDOORWAIT;
+ R_SoundNumForDoor(door); // haleyjd 09/15/10: [STRIFE] Get door sounds
+
+ // for proper sound - [STRIFE] - verified complete
+ switch(line->special)
+ {
+ case 117: // BLAZING DOOR RAISE
+ case 118: // BLAZING DOOR OPEN
+ S_StartSound(&sec->soundorg, sfx_bdopn);
+ break;
+
+ default: // NORMAL DOOR SOUND
+ S_StartSound(&sec->soundorg, door->opensound);
+ break;
+ }
+
+ // haleyjd: [STRIFE] - verified all.
+ switch(line->special)
+ {
+ case 1:
+ case 26:
+ case 27:
+ case 28:
+ door->type = normal;
+ break;
+
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 156: // villsa [STRIFE]
+ case 157: // villsa [STRIFE]
+ case 158: // villsa [STRIFE]
+ door->type = 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:
+ // haleyjd: [STRIFE] pretty important to have this here!
+ door->type = normal;
+ break;
+ }
+
+ // find the top and bottom of the movement range
+ door->topheight = P_FindLowestCeilingSurrounding(sec);
+ door->topheight -= 4*FRACUNIT;
+}
+
+
+//
+// Spawn a door that closes after 30 seconds
+//
+void P_SpawnDoorCloseIn30 (sector_t* sec)
+{
+ vldoor_t* door;
+
+ door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0);
+
+ P_AddThinker (&door->thinker);
+
+ sec->specialdata = door;
+ sec->special = 0;
+
+ door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
+ door->sector = sec;
+ door->direction = 0;
+ door->type = normal;
+ door->speed = VDOORSPEED;
+ door->topcountdown = 30 * TICRATE;
+}
+
+//
+// Spawn a door that opens after 5 minutes
+//
+void
+P_SpawnDoorRaiseIn5Mins
+( sector_t* sec,
+ int secnum )
+{
+ vldoor_t* door;
+
+ door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0);
+
+ P_AddThinker (&door->thinker);
+
+ sec->specialdata = door;
+ sec->special = 0;
+
+ door->thinker.function.acp1 = (actionf_p1)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 * TICRATE;
+}
+
+
+// villsa [STRIFE] resurrected sliding doors
+//
+
+//
+// villsa [STRIFE]
+//
+// Sliding door name information
+//
+static slidename_t slideFrameNames[MAXSLIDEDOORS] =
+{
+ // SIGLDR
+ {
+ "SIGLDR01", // frame1
+ "SIGLDR02", // frame2
+ "SIGLDR03", // frame3
+ "SIGLDR04", // frame4
+ "SIGLDR05", // frame5
+ "SIGLDR06", // frame6
+ "SIGLDR07", // frame7
+ "SIGLDR08" // frame8
+ },
+ // DORSTN
+ {
+ "DORSTN01", // frame1
+ "DORSTN02", // frame2
+ "DORSTN03", // frame3
+ "DORSTN04", // frame4
+ "DORSTN05", // frame5
+ "DORSTN06", // frame6
+ "DORSTN07", // frame7
+ "DORSTN08" // frame8
+ },
+
+ // DORQTR
+ {
+ "DORQTR01", // frame1
+ "DORQTR02", // frame2
+ "DORQTR03", // frame3
+ "DORQTR04", // frame4
+ "DORQTR05", // frame5
+ "DORQTR06", // frame6
+ "DORQTR07", // frame7
+ "DORQTR08" // frame8
+ },
+
+ // DORCRG
+ {
+ "DORCRG01", // frame1
+ "DORCRG02", // frame2
+ "DORCRG03", // frame3
+ "DORCRG04", // frame4
+ "DORCRG05", // frame5
+ "DORCRG06", // frame6
+ "DORCRG07", // frame7
+ "DORCRG08" // frame8
+ },
+
+ // DORCHN
+ {
+ "DORCHN01", // frame1
+ "DORCHN02", // frame2
+ "DORCHN03", // frame3
+ "DORCHN04", // frame4
+ "DORCHN05", // frame5
+ "DORCHN06", // frame6
+ "DORCHN07", // frame7
+ "DORCHN08" // frame8
+ },
+
+ // DORIRS
+ {
+ "DORIRS01", // frame1
+ "DORIRS02", // frame2
+ "DORIRS03", // frame3
+ "DORIRS04", // frame4
+ "DORIRS05", // frame5
+ "DORIRS06", // frame6
+ "DORIRS07", // frame7
+ "DORIRS08" // frame8
+ },
+
+ // DORALN
+ {
+ "DORALN01", // frame1
+ "DORALN02", // frame2
+ "DORALN03", // frame3
+ "DORALN04", // frame4
+ "DORALN05", // frame5
+ "DORALN06", // frame6
+ "DORALN07", // frame7
+ "DORALN08" // frame8
+ },
+
+ {"\0","\0","\0","\0","\0","\0","\0","\0"}
+};
+
+//
+// villsa [STRIFE]
+//
+// Sliding door open sounds
+//
+static sfxenum_t slideOpenSounds[MAXSLIDEDOORS] =
+{
+ sfx_drlmto, sfx_drston, sfx_airlck, sfx_drsmto,
+ sfx_drchno, sfx_airlck, sfx_airlck, sfx_None
+};
+
+//
+// villsa [STRIFE]
+//
+// Sliding door close sounds
+//
+static sfxenum_t slideCloseSounds[MAXSLIDEDOORS] =
+{
+ sfx_drlmtc, sfx_drston, sfx_airlck, sfx_drsmtc,
+ sfx_drchnc, sfx_airlck, sfx_airlck, sfx_None
+};
+
+slideframe_t slideFrames[MAXSLIDEDOORS];
+
+//
+// P_InitSlidingDoorFrames
+//
+// villsa [STRIFE] resurrected
+//
+void P_InitSlidingDoorFrames(void)
+{
+ int i;
+ int f1;
+ int f2;
+ int f3;
+ int f4;
+
+ memset(slideFrames, 0, sizeof(slideframe_t) * MAXSLIDEDOORS);
+
+ for(i = 0; i < MAXSLIDEDOORS; i++)
+ {
+ if(!slideFrameNames[i].frame1[0])
+ break;
+
+ f1 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame1));
+ f2 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame2));
+ f3 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame3));
+ f4 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame4));
+
+ slideFrames[i].frames[0] = f1;
+ slideFrames[i].frames[1] = f2;
+ slideFrames[i].frames[2] = f3;
+ slideFrames[i].frames[3] = f4;
+
+ f1 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame5));
+ f2 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame6));
+ f3 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame7));
+ f4 = R_TextureNumForName(DEH_String(slideFrameNames[i].frame8));
+
+ slideFrames[i].frames[4] = f1;
+ slideFrames[i].frames[5] = f2;
+ slideFrames[i].frames[6] = f3;
+ slideFrames[i].frames[7] = f4;
+ }
+}
+
+
+//
+// P_FindSlidingDoorType
+//
+// Return index into "slideFrames" array
+// for which door type to use
+//
+// villsa [STRIFE] resurrected
+//
+int P_FindSlidingDoorType(line_t* line)
+{
+ int i;
+ int val;
+
+ for(i = 0; i < MAXSLIDEDOORS-1; i++)
+ {
+ val = sides[line->sidenum[0]].toptexture;
+ if(val == slideFrames[i].frames[0])
+ return i;
+ }
+
+ return -1;
+}
+
+//
+// T_SlidingDoor
+//
+// villsa [STRIFE] resurrected
+//
+void T_SlidingDoor(slidedoor_t* door)
+{
+ sector_t* sec;
+
+ sec = door->frontsector;
+
+ switch(door->status)
+ {
+ case sd_opening:
+ if(!door->timer--)
+ {
+ if(++door->frame == SNUMFRAMES)
+ {
+ // IF DOOR IS DONE OPENING...
+ door->line1->flags &= ~ML_BLOCKING;
+ door->line2->flags &= ~ML_BLOCKING;
+
+ if(door->type == sdt_openOnly)
+ {
+ door->frontsector->specialdata = NULL;
+ P_RemoveThinker (&door->thinker);
+ return;
+ }
+
+ door->timer = SDOORWAIT;
+ door->status = sd_waiting;
+ }
+ else
+ {
+ // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME...
+ door->timer = SWAITTICS;
+
+ sides[door->line2->sidenum[0]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line2->sidenum[1]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line1->sidenum[0]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line1->sidenum[1]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+ }
+ }
+
+ return;
+
+ case sd_waiting:
+ // IF DOOR IS DONE WAITING...
+ if(!door->timer--)
+ {
+ fixed_t speed;
+ fixed_t cheight;
+
+ sec = door->frontsector;
+
+ // CAN DOOR CLOSE?
+ if(sec->thinglist != NULL)
+ {
+ door->timer = SDOORWAIT;
+ return;
+ }
+ else
+ {
+
+ cheight = sec->ceilingheight;
+ speed = cheight - sec->floorheight - (10*FRACUNIT);
+
+ // something blocking it?
+ if(T_MovePlane(sec, speed, sec->floorheight, 0, 1, -1) == crushed)
+ {
+ door->timer = SDOORWAIT;
+ return;
+ }
+ else
+ {
+ // Instantly move plane
+ T_MovePlane(sec, (128*FRACUNIT), cheight, 0, 1, 1);
+
+ // turn line blocking back on
+ door->line1->flags |= ML_BLOCKING;
+ door->line2->flags |= ML_BLOCKING;
+
+ // play close sound
+ S_StartSound(&sec->soundorg, slideCloseSounds[door->whichDoorIndex]);
+
+ door->status = sd_closing;
+ door->timer = SWAITTICS;
+ }
+ }
+ }
+
+ return;
+
+ case sd_closing:
+ if (!door->timer--)
+ {
+ if(--door->frame < 0)
+ {
+ // IF DOOR IS DONE CLOSING...
+ T_MovePlane(sec, (128*FRACUNIT), sec->floorheight, 0, 1, -1);
+ door->frontsector->specialdata = NULL;
+ P_RemoveThinker (&door->thinker);
+ return;
+ }
+ else
+ {
+ // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME...
+ door->timer = SWAITTICS;
+
+ sides[door->line2->sidenum[0]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line2->sidenum[1]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line1->sidenum[0]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+
+ sides[door->line1->sidenum[1]].midtexture =
+ slideFrames[door->whichDoorIndex].frames[door->frame];
+ }
+ }
+
+ return;
+ }
+}
+
+//
+// EV_RemoteSlidingDoor
+//
+// villsa [STRIFE] new function
+//
+int EV_RemoteSlidingDoor(line_t* line, mobj_t* thing)
+{
+ int secnum;
+ sector_t* sec;
+ int i;
+ int rtn;
+ line_t* secline;
+
+ secnum = -1;
+ rtn = 0;
+
+ while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if(sec->specialdata)
+ continue;
+
+ for(i = 0; i < 4; i++)
+ {
+ secline = sec->lines[i];
+
+ if(P_FindSlidingDoorType(secline) < 0)
+ continue;
+
+ EV_SlidingDoor(secline, thing);
+ rtn = 1;
+ }
+ }
+
+ return rtn;
+}
+
+
+//
+// EV_SlidingDoor
+//
+// villsa [STRIFE]
+//
+void EV_SlidingDoor(line_t* line, mobj_t* thing)
+{
+ sector_t* sec;
+ slidedoor_t* door;
+ int i;
+ line_t* secline;
+
+ // Make sure door isn't already being animated
+ sec = sides[line->sidenum[1]].sector;
+ door = NULL;
+ if(sec->specialdata)
+ {
+ if (!thing->player)
+ return;
+
+ door = sec->specialdata;
+ if(door->type == sdt_openAndClose)
+ {
+ if(door->status == sd_waiting)
+ {
+ door->status = sd_closing;
+ door->timer = SWAITTICS; // villsa [STRIFE]
+ }
+ }
+ else
+ return;
+ }
+
+ // Init sliding door vars
+ if(!door)
+ {
+ door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
+ P_AddThinker (&door->thinker);
+
+ sec->specialdata = door;
+
+ door->type = sdt_openAndClose;
+ door->status = sd_opening;
+ door->whichDoorIndex = P_FindSlidingDoorType(line);
+
+ // villsa [STRIFE] different error message
+ if(door->whichDoorIndex < 0)
+ I_Error(DEH_String("EV_SlidingDoor: Textures are not defined for sliding door!"));
+
+ sides[line->sidenum[0]].midtexture = sides[line->sidenum[0]].toptexture;
+
+ // villsa [STRIFE]
+ door->line1 = line;
+ door->line2 = line;
+
+ // villsa [STRIFE] this loop assumes that the sliding door is made up
+ // of only four linedefs!
+ for(i = 0; i < 4; i++)
+ {
+ secline = sec->lines[i];
+ if(secline != line)
+ {
+ side_t* side1;
+ side_t* side2;
+
+ side1 = &sides[secline->sidenum[0]];
+ side2 = &sides[line->sidenum[0]];
+
+ if(side1->toptexture == side2->toptexture)
+ door->line2 = secline;
+ }
+ }
+
+ door->thinker.function.acp1 = (actionf_p1)T_SlidingDoor;
+ door->timer = SWAITTICS;
+ door->frontsector = sec;
+ door->frame = 0;
+
+ // villsa [STRIFE] preset flags
+ door->line1->flags |= ML_BLOCKING;
+ door->line2->flags |= ML_BLOCKING;
+
+ // villsa [STRIFE] set the closing sector
+ T_MovePlane(
+ door->frontsector,
+ (128*FRACUNIT),
+ P_FindLowestCeilingSurrounding(door->frontsector),
+ 0,
+ 1,
+ 1);
+
+ // villsa [STRIFE] play open sound
+ S_StartSound(&door->frontsector->soundorg, slideOpenSounds[door->whichDoorIndex]);
+ }
+}
+
diff --git a/src/strife/p_enemy.c b/src/strife/p_enemy.c
new file mode 100644
index 00000000..684d6b27
--- /dev/null
+++ b/src/strife/p_enemy.c
@@ -0,0 +1,3373 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+#include <stdlib.h>
+
+#include "m_random.h"
+#include "i_system.h"
+#include "doomdef.h"
+#include "p_local.h"
+#include "s_sound.h"
+#include "g_game.h"
+#include "z_zone.h" // villsa [STRIFE]
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "sounds.h"
+
+// [STRIFE] Dialog / Inventory
+#include "p_dialog.h"
+#include "deh_str.h"
+#include "w_wad.h"
+#include "f_finale.h"
+#include "p_inter.h"
+
+// Forward Declarations:
+void A_RandomWalk(mobj_t *);
+void A_ProgrammerAttack(mobj_t* actor);
+void A_FireSigilEOffshoot(mobj_t *actor);
+void A_SpectreCAttack(mobj_t *actor);
+void A_SpectreDAttack(mobj_t *actor);
+void A_SpectreEAttack(mobj_t *actor);
+
+void P_ThrustMobj(mobj_t *actor, angle_t angle, fixed_t force);
+
+typedef enum
+{
+ DI_EAST,
+ DI_NORTHEAST,
+ DI_NORTH,
+ DI_NORTHWEST,
+ DI_WEST,
+ DI_SOUTHWEST,
+ DI_SOUTH,
+ DI_SOUTHEAST,
+ DI_NODIR,
+ NUMDIRS
+
+} dirtype_t;
+
+
+//
+// P_NewChaseDir related LUT.
+//
+dirtype_t opposite[] =
+{
+ DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
+ DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
+};
+
+dirtype_t diags[] =
+{
+ DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
+};
+
+
+
+
+
+void A_Fall (mobj_t *actor);
+
+
+//
+// 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.
+//
+// haleyjd 09/05/10: [STRIFE] Verified unmodified
+//
+
+mobj_t* soundtarget;
+
+void
+P_RecursiveSound
+( sector_t* sec,
+ int soundblocks )
+{
+ int i;
+ line_t* check;
+ sector_t* other;
+
+ // 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;
+ sec->soundtarget = soundtarget;
+
+ for (i=0 ;i<sec->linecount ; i++)
+ {
+ check = sec->lines[i];
+ if (! (check->flags & ML_TWOSIDED) )
+ continue;
+
+ P_LineOpening (check);
+
+ if (openrange <= 0)
+ continue; // closed door
+
+ if ( sides[ check->sidenum[0] ].sector == sec)
+ other = sides[ check->sidenum[1] ] .sector;
+ else
+ other = sides[ check->sidenum[0] ].sector;
+
+ if (check->flags & ML_SOUNDBLOCK)
+ {
+ if (!soundblocks)
+ P_RecursiveSound (other, 1);
+ }
+ else
+ P_RecursiveSound (other, soundblocks);
+ }
+}
+
+
+
+//
+// P_NoiseAlert
+// If a monster yells at a player,
+// it will alert other monsters to the player.
+//
+// haleyjd 09/05/10: [STRIFE] Verified unmodified
+//
+void
+P_NoiseAlert
+( mobj_t* target,
+ mobj_t* emmiter )
+{
+ soundtarget = target;
+ validcount++;
+ P_RecursiveSound (emmiter->subsector->sector, 0);
+}
+
+//
+// P_WakeUpThing
+//
+// villsa [STRIFE] New function
+// Wakes up an mobj.nearby when somebody has been punched.
+//
+static void P_WakeUpThing(mobj_t* puncher, mobj_t* bystander)
+{
+ if(!(bystander->flags & MF_NODIALOG))
+ {
+ bystander->target = puncher;
+ if(bystander->info->seesound)
+ S_StartSound(bystander, bystander->info->seesound);
+ P_SetMobjState(bystander, bystander->info->seestate);
+ }
+}
+
+//
+// P_DoPunchAlert
+//
+// villsa [STRIFE] New function (by Quasar ;)
+// Wake up buddies nearby when the player thinks he's gotten too clever
+// with the punch dagger. Walks sector links.
+//
+void P_DoPunchAlert(mobj_t *puncher, mobj_t *punchee)
+{
+ mobj_t *rover;
+
+ // don't bother with this crap if we're already on alert
+ if(punchee->subsector->sector->soundtarget)
+ return;
+
+ // gotta still be alive to call for help
+ if(punchee->health <= 0)
+ return;
+
+ // has to be something you can wake up and kill too
+ if(!(punchee->flags & MF_COUNTKILL) || punchee->flags & MF_NODIALOG)
+ return;
+
+ // make the punchee hurt - haleyjd 09/05/10: Fixed to use painstate.
+ punchee->target = puncher;
+ P_SetMobjState(punchee, punchee->info->painstate);
+
+ // wake up everybody nearby
+
+ // scan forward on sector list
+ for(rover = punchee->snext; rover; rover = rover->snext)
+ {
+ // we only wake up certain thing types (Acolytes and Templars?)
+ if(rover->health > 0 && rover->type >= MT_GUARD1 && rover->type <= MT_PGUARD &&
+ (P_CheckSight(rover, puncher) || P_CheckSight(rover, punchee)))
+ {
+ P_WakeUpThing(puncher, rover);
+ rover->flags |= MF_NODIALOG;
+ }
+ }
+
+ // scan backward on sector list
+ for(rover = punchee->sprev; rover; rover = rover->sprev)
+ {
+ // we only wake up certain thing types (Acolytes and Templars?)
+ if(rover->health > 0 && rover->type >= MT_GUARD1 && rover->type <= MT_PGUARD &&
+ (P_CheckSight(rover, puncher) || P_CheckSight(rover, punchee)))
+ {
+ P_WakeUpThing(puncher, rover);
+ rover->flags |= MF_NODIALOG;
+ }
+ }
+}
+
+
+
+
+//
+// P_CheckMeleeRange
+//
+// [STRIFE] Minor change to meleerange.
+//
+boolean P_CheckMeleeRange(mobj_t* actor)
+{
+ mobj_t* pl;
+ fixed_t dist;
+
+ if(!actor->target)
+ return false;
+
+ pl = actor->target;
+ if(actor->z + 3 * actor->height / 2 < pl->z) // villsa [STRIFE]
+ return false;
+
+ dist = P_AproxDistance(pl->x - actor->x, pl->y - actor->y);
+
+ if(dist >= MELEERANGE - 20*FRACUNIT + pl->info->radius)
+ return false;
+
+ if(!P_CheckSight (actor, actor->target))
+ return false;
+
+ return true;
+}
+
+//
+// P_CheckMissileRange
+//
+// [STRIFE]
+// Changes to eliminate DOOM-specific code and to allow for
+// varying attack ranges for Strife monsters, as well as a general tweak
+// to considered distance for all monsters.
+//
+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;
+ return true;
+ }
+
+ 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 >>= 16;
+
+ // villsa [STRIFE] checks for acolytes
+ // haleyjd 09/05/10: Repaired to match disassembly: Was including
+ // SHADOWGUARD in the wrong case, was missing MT_SENTINEL entirely.
+ // Structure of ASM also indicates this was probably a switch
+ // statement turned into a cascading if/else by the compiler.
+ switch(actor->type)
+ {
+ case MT_GUARD1:
+ case MT_GUARD2:
+ case MT_GUARD3:
+ case MT_GUARD4:
+ case MT_GUARD5:
+ case MT_GUARD6:
+ // oddly, not all Acolytes are included here...
+ dist >>= 4;
+ break;
+ case MT_SHADOWGUARD:
+ case MT_CRUSADER:
+ case MT_SENTINEL:
+ dist >>= 1;
+ break;
+ default:
+ break;
+ }
+
+ // villsa [STRIFE] changed to 150
+ if (dist > 150)
+ dist = 150;
+
+ // haleyjd 20100910: Hex-Rays was leaving this out completely:
+ if (actor->type == MT_CRUSADER && dist > 120)
+ dist = 120;
+
+ // haleyjd 20110224 [STRIFE]: reversed predicate
+ return (dist < P_Random());
+}
+
+//
+// P_CheckRobotRange
+//
+// villsa [STRIFE] New function
+//
+boolean P_CheckRobotRange(mobj_t *actor)
+{
+ fixed_t dist;
+
+ if(!P_CheckSight(actor, actor->target))
+ return false;
+
+ if(actor->reactiontime)
+ return false; // do not attack yet
+
+ dist = (P_AproxDistance(actor->x-actor->target->x,
+ actor->y-actor->target->y) - 64*FRACUNIT) >> FRACBITS;
+
+ return (dist < 200);
+}
+
+
+//
+// P_Move
+// Move in the current direction,
+// returns false if the move is blocked.
+//
+// [STRIFE]
+// villsa/haleyjd 09/05/10: Modified for terrain types and 3D object
+// clipping. Below constants are verified to be unmodified:
+//
+fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
+fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
+
+#define MAXSPECIALCROSS 8
+
+extern line_t* spechit[MAXSPECIALCROSS];
+extern int numspechit;
+
+boolean P_Move (mobj_t* actor)
+{
+ fixed_t tryx;
+ fixed_t tryy;
+
+ line_t* ld;
+
+ // warning: 'catch', 'throw', and 'try'
+ // are all C++ reserved words
+ boolean try_ok;
+ boolean good;
+
+ if (actor->movedir == DI_NODIR)
+ return false;
+
+ if ((unsigned)actor->movedir >= 8)
+ I_Error ("Weird actor->movedir!");
+
+ tryx = actor->x + actor->info->speed*xspeed[actor->movedir];
+ tryy = actor->y + actor->info->speed*yspeed[actor->movedir];
+
+ try_ok = P_TryMove (actor, tryx, tryy);
+
+ if (!try_ok)
+ {
+ // open any specials
+ if (actor->flags & MF_FLOAT && floatok)
+ {
+ // must adjust height
+ if (actor->z < tmfloorz)
+ actor->z += FLOATSPEED; // [STRIFE] Note FLOATSPEED == 5*FRACUNIT
+ else
+ actor->z -= FLOATSPEED;
+
+ actor->flags |= MF_INFLOAT;
+ return true;
+ }
+
+ if (!numspechit)
+ return false;
+
+ actor->movedir = DI_NODIR;
+ good = false;
+ while (numspechit--)
+ {
+ ld = spechit[numspechit];
+ // if the special is not a door
+ // that can be opened,
+ // return false
+ if (P_UseSpecialLine (actor, ld,0))
+ good = true;
+ }
+ return good;
+ }
+ else
+ {
+ actor->flags &= ~(MF_INFLOAT|MF_FEETCLIPPED); // villsa [STRIFE]
+
+ // villsa [STRIFE]
+ if(P_GetTerrainType(actor) != FLOOR_SOLID)
+ actor->flags |= MF_FEETCLIPPED;
+ }
+
+
+ // villsa [STRIFE] Removed pulling non-floating actors down to the ground.
+ // (haleyjd 09/05/10: Verified)
+ /*if (! (actor->flags & MF_FLOAT) )
+ actor->z = actor->floorz;*/
+
+ 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.
+//
+// haleyjd 09/05/10: [STRIFE] Verified unmodified.
+//
+boolean P_TryWalk (mobj_t* actor)
+{
+ if (!P_Move (actor))
+ {
+ return false;
+ }
+
+ actor->movecount = P_Random()&15;
+ return true;
+}
+
+
+
+//
+// P_NewChaseDir
+//
+
+void P_NewChaseDir(mobj_t* actor)
+{
+ fixed_t deltax;
+ fixed_t deltay;
+
+ dirtype_t d[3];
+
+ int tdir;
+ dirtype_t olddir;
+
+ dirtype_t turnaround;
+
+ // villsa [STRIFE] don't bomb out and instead set spawnstate
+ if(!actor->target)
+ {
+ //I_Error("P_NewChaseDir: called with no target");
+ P_SetMobjState(actor, actor->info->spawnstate);
+ return;
+ }
+
+ olddir = actor->movedir;
+ turnaround=opposite[olddir];
+
+ deltax = actor->target->x - actor->x;
+ deltay = actor->target->y - actor->y;
+
+ if (deltax>10*FRACUNIT)
+ d[1]= DI_EAST;
+ else if (deltax<-10*FRACUNIT)
+ d[1]= DI_WEST;
+ else
+ d[1]=DI_NODIR;
+
+ if (deltay<-10*FRACUNIT)
+ d[2]= DI_SOUTH;
+ else if (deltay>10*FRACUNIT)
+ d[2]= DI_NORTH;
+ else
+ d[2]=DI_NODIR;
+
+ // try direct route
+ if (d[1] != DI_NODIR
+ && d[2] != DI_NODIR)
+ {
+ actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
+ if (actor->movedir != (int) turnaround && P_TryWalk(actor))
+ return;
+ }
+
+ // try other directions
+ if (P_Random() > 200
+ || abs(deltay)>abs(deltax))
+ {
+ tdir=d[1];
+ d[1]=d[2];
+ d[2]=tdir;
+ }
+
+ if (d[1]==turnaround)
+ d[1]=DI_NODIR;
+ if (d[2]==turnaround)
+ d[2]=DI_NODIR;
+
+ if (d[1]!=DI_NODIR)
+ {
+ actor->movedir = d[1];
+ if (P_TryWalk(actor))
+ {
+ // either moved forward or attacked
+ return;
+ }
+ }
+
+ if (d[2]!=DI_NODIR)
+ {
+ actor->movedir =d[2];
+
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ // there is no direct path to the player,
+ // so pick another direction.
+ if (olddir!=DI_NODIR)
+ {
+ actor->movedir =olddir;
+
+ if (P_TryWalk(actor))
+ return;
+ }
+
+ // randomly determine direction of search
+ if (P_Random()&1)
+ {
+ for ( tdir=DI_EAST;
+ tdir<=DI_SOUTHEAST;
+ tdir++ )
+ {
+ if (tdir != (int) turnaround)
+ {
+ actor->movedir =tdir;
+
+ if ( P_TryWalk(actor) )
+ return;
+ }
+ }
+ }
+ else
+ {
+ for ( tdir=DI_SOUTHEAST;
+ tdir != (DI_EAST-1);
+ tdir-- )
+ {
+ if (tdir != (int) turnaround)
+ {
+ actor->movedir = tdir;
+
+ if ( P_TryWalk(actor) )
+ return;
+ }
+ }
+ }
+
+ if (turnaround != DI_NODIR)
+ {
+ actor->movedir =turnaround;
+ if ( P_TryWalk(actor) )
+ return;
+ }
+
+ actor->movedir = DI_NODIR; // can not move
+}
+
+//
+// P_NewRandomDir
+//
+// villsa [STRIFE] new function
+//
+// haleyjd: Almost identical to the tail-end of P_NewChaseDir, this function
+// finds a purely random direction for an object to walk. Called from
+// A_RandomWalk.
+//
+// Shockingly similar to the RandomWalk pointer in Eternity :)
+//
+void P_NewRandomDir(mobj_t* actor)
+{
+ int dir = 0;
+ int omovedir = opposite[actor->movedir]; // haleyjd 20110223: nerfed this...
+
+ // randomly determine direction of search
+ if(P_Random() & 1)
+ {
+ // Try all non-reversal directions forward, first
+ for(dir = 0; dir < DI_NODIR; dir++)
+ {
+ if(dir != omovedir)
+ {
+ actor->movedir = dir;
+ if(P_Random() & 1)
+ {
+ if(P_TryWalk(actor))
+ break;
+ }
+ }
+ }
+
+ // haleyjd 20110223: logic missing entirely:
+ // failed all non-reversal directions? try reversing
+ if(dir > DI_SOUTHEAST)
+ {
+ if(omovedir == DI_NODIR)
+ {
+ actor->movedir = DI_NODIR;
+ return;
+ }
+ actor->movedir = omovedir;
+ if(P_TryWalk(actor))
+ return;
+ else
+ {
+ actor->movedir = DI_NODIR;
+ return;
+ }
+ }
+ }
+ else
+ {
+ // Try directions one at a time in backward order
+ dir = DI_SOUTHEAST;
+ while(1)
+ {
+ // haleyjd 09/05/10: missing random code.
+ if(dir != omovedir)
+ {
+ actor->movedir = dir;
+
+ // villsa 09/06/10: un-inlined code
+ if(P_TryWalk(actor))
+ return;
+ }
+
+ // Ran out of non-reversal directions to try? Reverse.
+ if(--dir == -1)
+ {
+ if(omovedir == DI_NODIR)
+ {
+ actor->movedir = DI_NODIR;
+ return;
+ }
+ actor->movedir = omovedir;
+ // villsa 09/06/10: un-inlined code
+ if(P_TryWalk(actor))
+ return;
+ else
+ {
+ actor->movedir = DI_NODIR;
+ return;
+ }
+ } // end if(--dir == -1)
+ } // end while(1)
+ } // end else
+}
+
+// haleyjd 09/05/10: Needed below.
+extern void P_BulletSlope (mobj_t *mo);
+
+//
+// P_LookForPlayers
+//
+// If allaround is false, only look 180 degrees in front.
+// Returns true if a player is targeted.
+//
+// [STRIFE]
+// haleyjd 09/05/10: Modifications to support friendly units.
+//
+boolean
+P_LookForPlayers
+( mobj_t* actor,
+ boolean allaround )
+{
+ int c;
+ int stop;
+ player_t* player;
+ angle_t an;
+ fixed_t dist;
+ mobj_t * master = players[actor->miscdata].mo;
+
+ // haleyjd 09/05/10: handle Allies
+ if(actor->flags & MF_ALLY)
+ {
+ // Deathmatch: support team behavior for Rebels.
+ if(netgame)
+ {
+ // Rebels adopt the allied player's target if it is not of the same
+ // allegiance. Other allies do it unconditionally.
+ if(master && master->target &&
+ (master->target->type != MT_REBEL1 ||
+ master->target->miscdata != actor->miscdata))
+ {
+ actor->target = master->target;
+ }
+ else
+ {
+ // haleyjd 09/06/10: Note that this sets actor->target in Strife!
+ P_BulletSlope(actor);
+
+ // Clear target if nothing is visible, or if the target is a
+ // friendly Rebel or the allied player.
+ if (linetarget == NULL
+ || (actor->target->type == MT_REBEL1
+ && actor->target->miscdata == actor->miscdata)
+ || actor->target == master)
+ {
+ actor->target = NULL;
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // Single-player: Adopt any non-allied player target.
+ if(master && master->target && !(master->target->flags & MF_ALLY))
+ {
+ actor->target = master->target;
+ return true;
+ }
+
+ // haleyjd 09/06/10: Note that this sets actor->target in Strife!
+ P_BulletSlope(actor);
+
+ // Clear target if nothing is visible, or if the target is an ally.
+ if(!linetarget || actor->target->flags & MF_ALLY)
+ {
+ actor->target = NULL;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ c = 0;
+
+ // NOTE: This behavior has been changed from the Vanilla behavior, where
+ // an infinite loop can occur if players 0-3 all quit the game. Although
+ // technically this is not what Vanilla does, fixing this is highly
+ // desirable, and having the game simply lock up is not acceptable.
+ // stop = (actor->lastlook - 1) & 3;
+ // for (;; actor->lastlook = (actor->lastlook + 1) & 3)
+
+ stop = (actor->lastlook + MAXPLAYERS - 1) % MAXPLAYERS;
+
+ for ( ; ; actor->lastlook = (actor->lastlook + 1) % MAXPLAYERS)
+ {
+ if (!playeringame[actor->lastlook])
+ continue;
+
+ if (c++ == 2
+ || actor->lastlook == stop)
+ {
+ // done looking
+ return false;
+ }
+
+ player = &players[actor->lastlook];
+
+ if (player->health <= 0)
+ continue; // dead
+
+ if (!P_CheckSight (actor, player->mo))
+ continue; // out of sight
+
+ if (!allaround)
+ {
+ an = R_PointToAngle2(actor->x,
+ actor->y,
+ player->mo->x,
+ player->mo->y) - actor->angle;
+
+ if (an > ANG90 && an < ANG270)
+ {
+ dist = P_AproxDistance (player->mo->x - actor->x,
+ player->mo->y - actor->y);
+ // if real close, react anyway
+ if (dist > MELEERANGE)
+ continue; // behind back
+ }
+ }
+
+ actor->target = player->mo;
+ return true;
+ }
+
+ return false;
+}
+
+// haleyjd 09/05/10: [STRIFE] Removed A_KeenDie
+
+//
+// ACTION ROUTINES
+//
+
+//
+// A_Look
+// Stay in state until a player is sighted.
+//
+// [STRIFE]
+// haleyjd 09/05/10: Adjusted for allies, Inquisitors, etc.
+//
+void A_Look (mobj_t* actor)
+{
+ mobj_t* targ;
+
+ actor->threshold = 0; // any shot will wake up
+ targ = actor->subsector->sector->soundtarget;
+
+ if (targ
+ && (targ->flags & MF_SHOOTABLE) )
+ {
+ // [STRIFE] Allies wander when they call this.
+ if(actor->flags & MF_ALLY)
+ A_RandomWalk(actor);
+ else
+ {
+ actor->target = targ;
+
+ if ( actor->flags & MF_AMBUSH )
+ {
+ if (P_CheckSight (actor, actor->target))
+ goto seeyou;
+ }
+ else
+ goto seeyou;
+ }
+ }
+
+ // haleyjd 09/05/10: This is bizarre, as Rogue keeps using the GIVEQUEST flag
+ // as a parameter to control allaround look behavior. Did they just run out of
+ // flags, or what?
+ // STRIFE-TODO: Needs serious verification.
+ if (!P_LookForPlayers (actor, actor->flags & MF_GIVEQUEST) )
+ return;
+
+ // go into chase state
+seeyou:
+ if (actor->info->seesound)
+ {
+ int sound = actor->info->seesound;
+ mobj_t * emitter = actor;
+
+ // [STRIFE] Removed DOOM random sounds.
+
+ // [STRIFE] Only Inquisitors roar loudly here.
+ if (actor->type == MT_INQUISITOR)
+ emitter = NULL;
+
+ S_StartSound (emitter, sound);
+ }
+
+ // [STRIFE] Set threshold (kinda odd as it's still set to 0 above...)
+ actor->threshold = 20;
+
+ P_SetMobjState (actor, actor->info->seestate);
+}
+
+//
+// A_RandomWalk
+//
+// [STRIFE] New function.
+// haleyjd 09/05/10: Action routine used to meander about.
+//
+void A_RandomWalk(mobj_t* actor)
+{
+ // Standing actors do not wander.
+ if(actor->flags & MF_STAND)
+ return;
+
+ if(actor->reactiontime)
+ actor->reactiontime--; // count down reaction time
+ else
+ {
+ // turn to a new angle
+ if(actor->movedir < DI_NODIR)
+ {
+ int delta;
+
+ actor->angle &= (7 << 29);
+ delta = actor->angle - (actor->movedir << 29);
+
+ if(delta < 0)
+ actor->angle += ANG90/2;
+ else if(delta > 0)
+ actor->angle -= ANG90/2;
+ }
+
+ // try moving
+ if(--actor->movecount < 0 || !P_Move(actor))
+ {
+ P_NewRandomDir(actor);
+ actor->movecount += 5;
+ }
+ }
+}
+
+//
+// A_FriendLook
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Action function used mostly by mundane characters such as
+// peasants.
+//
+void A_FriendLook(mobj_t* actor)
+{
+ mobj_t *soundtarget = actor->subsector->sector->soundtarget;
+
+ actor->threshold = 0;
+
+ if(soundtarget && soundtarget->flags & MF_SHOOTABLE)
+ {
+ // Handle allies, except on maps 3 and 34 (Front Base/Movement Base)
+ if((actor->flags & MF_ALLY) == (soundtarget->flags & MF_ALLY) &&
+ gamemap != 3 && gamemap != 34)
+ {
+ // STRIFE-TODO: Needs serious verification.
+ if(P_LookForPlayers(actor, actor->flags & MF_GIVEQUEST))
+ {
+ P_SetMobjState(actor, actor->info->seestate);
+ actor->flags |= MF_NODIALOG;
+ return;
+ }
+ }
+ else
+ {
+ actor->target = soundtarget;
+
+ if(!(actor->flags & MF_AMBUSH) || P_CheckSight(actor, actor->target))
+ {
+ actor->threshold = 10;
+ P_SetMobjState(actor, actor->info->seestate);
+ return;
+ }
+ }
+ }
+
+ // do some idle animation
+ if(P_Random() < 30)
+ {
+ int t = P_Random();
+ P_SetMobjState(actor, (t & 1) + actor->info->spawnstate + 1);
+ }
+
+ // wander around a bit
+ if(!(actor->flags & MF_STAND) && P_Random() < 40)
+ P_SetMobjState(actor, actor->info->spawnstate + 3);
+}
+
+//
+// A_Listen
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Action routine used to strictly listen for a target.
+//
+void A_Listen(mobj_t* actor)
+{
+ mobj_t *soundtarget;
+
+ actor->threshold = 0;
+
+ soundtarget = actor->subsector->sector->soundtarget;
+
+ if(soundtarget && (soundtarget->flags & MF_SHOOTABLE))
+ {
+ if((actor->flags & MF_ALLY) != (soundtarget->flags & MF_ALLY))
+ {
+ actor->target = soundtarget;
+
+ if(!(actor->flags & MF_AMBUSH) || P_CheckSight(actor, actor->target))
+ {
+ if(actor->info->seesound)
+ S_StartSound(actor, actor->info->seesound);
+
+ actor->threshold = 10;
+
+ P_SetMobjState(actor, actor->info->seestate);
+ }
+ }
+ }
+}
+
+
+//
+// A_Chase
+// Actor has a melee attack,
+// so it tries to close as fast as possible
+//
+// haleyjd 09/05/10: [STRIFE] Various minor changes
+//
+void A_Chase (mobj_t* actor)
+{
+ int delta;
+
+ if (actor->reactiontime)
+ actor->reactiontime--;
+
+ // modify target threshold
+ if (actor->threshold)
+ {
+ // haleyjd 20110204 [STRIFE]: No health <= 0 check here!
+ if (actor->target)
+ actor->threshold--;
+ else
+ actor->threshold = 0;
+ }
+
+ // turn towards movement direction if not there yet
+ if (actor->movedir < 8)
+ {
+ actor->angle &= (7<<29);
+ delta = actor->angle - (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))
+ {
+ // look for a new target
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+
+ P_SetMobjState (actor, actor->info->spawnstate);
+ return;
+ }
+
+ // do not attack twice in a row
+ if (actor->flags & MF_JUSTATTACKED)
+ {
+ actor->flags &= ~MF_JUSTATTACKED;
+ // [STRIFE] Checks only against fastparm, not gameskill == 5
+ if (!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);
+ return;
+ }
+
+ // check for missile attack
+ if (actor->info->missilestate)
+ {
+ // [STRIFE] Checks only fastparm.
+ if (!fastparm && actor->movecount)
+ {
+ goto nomissile;
+ }
+
+ if (!P_CheckMissileRange (actor))
+ goto nomissile;
+
+ P_SetMobjState (actor, actor->info->missilestate);
+
+ // [STRIFE] Add NODIALOG flag to disable dialog
+ actor->flags |= (MF_NODIALOG|MF_JUSTATTACKED);
+ return;
+ }
+
+ // ?
+nomissile:
+ // possibly choose another target
+ if (netgame
+ && !actor->threshold
+ && !P_CheckSight (actor, actor->target) )
+ {
+ if (P_LookForPlayers(actor, true))
+ return; // got a new target
+ }
+
+ // chase towards player
+ if (--actor->movecount<0
+ || !P_Move (actor))
+ {
+ P_NewChaseDir (actor);
+ }
+
+ // [STRIFE] Changes to active sound behavior:
+ // * Significantly more frequent
+ // * Acolytes have randomized wandering sounds
+
+ // make active sound
+ if (actor->info->activesound && P_Random () < 38)
+ {
+ if(actor->info->activesound >= sfx_agrac1 &&
+ actor->info->activesound <= sfx_agrac4)
+ {
+ S_StartSound(actor, sfx_agrac1 + P_Random() % 4);
+ }
+ else
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+
+//
+// A_FaceTarget
+//
+// [STRIFE]
+// haleyjd 09/05/10: Handling for visibility-modifying flags.
+//
+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)
+ {
+ // [STRIFE] increased SHADOW inaccuracy by a power of 2
+ int t = P_Random();
+ actor->angle += (t - P_Random()) << 22;
+ }
+ else if(actor->target->flags & MF_MVIS)
+ {
+ // [STRIFE] MVIS gives even worse aiming!
+ int t = P_Random();
+ actor->angle += (t - P_Random()) << 23;
+ }
+}
+
+//
+// A_PeasantPunch
+//
+// [STRIFE] New function
+// haleyjd 09/05/10: Attack used by Peasants as a one-time retaliation
+// when the player or a monster injures them. Weak doesn't begin to
+// describe it :P
+//
+void A_PeasantPunch(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+ if(P_CheckMeleeRange(actor))
+ P_DamageMobj(actor->target, actor, actor, 2 * (P_Random() % 5) + 2);
+}
+
+//
+// A_ReaverAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action routine used by Reavers to fire bullets.
+// Also apparently used by Inquistors, though they don't seem to use
+// it too often, as they're content to blow your face off with their
+// HE grenades instead.
+//
+void A_ReaverAttack(mobj_t* actor)
+{
+ int i = 0;
+ fixed_t slope;
+
+ if(!actor->target)
+ return;
+
+ S_StartSound(actor, sfx_reavat);
+ A_FaceTarget(actor);
+
+ slope = P_AimLineAttack(actor, actor->angle, 2048*FRACUNIT);
+
+ do
+ {
+ int t = P_Random();
+ angle_t shootangle = actor->angle + ((t - P_Random()) << 20);
+ int damage = (P_Random() & 7) + 1;
+
+ P_LineAttack(actor, shootangle, 2048*FRACUNIT, slope, damage);
+ ++i;
+ }
+ while(i < 3);
+}
+
+//
+// A_BulletAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for generic bullet attacks. Used by
+// a lot of different characters, including Acolytes, Rebels, and Macil.
+//
+void A_BulletAttack(mobj_t* actor)
+{
+ int t, damage;
+ fixed_t slope;
+ angle_t shootangle;
+
+ if(!actor->target)
+ return;
+
+ S_StartSound(actor, sfx_rifle);
+ A_FaceTarget(actor);
+
+ slope = P_AimLineAttack(actor, actor->angle, 2048*FRACUNIT);
+ t = P_Random();
+ shootangle = ((t - P_Random()) << 19) + actor->angle;
+ damage = 3 * (P_Random() % 5 + 1);
+
+ P_LineAttack(actor, shootangle, 2048*FRACUNIT, slope, damage);
+}
+
+//
+// A_CheckTargetVisible
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action routine which sets a thing back to its
+// seestate at random, or if it cannot see its target, or its target
+// is dead. Used by diverse actors.
+//
+void A_CheckTargetVisible(mobj_t* actor)
+{
+ A_FaceTarget(actor);
+
+ if(P_Random() >= 30)
+ {
+ mobj_t *target = actor->target;
+
+ if(!target || target->health <= 0 || !P_CheckSight(actor, target) ||
+ P_Random() < 40)
+ {
+ P_SetMobjState(actor, actor->info->seestate);
+ }
+ }
+}
+
+//
+// A_SentinelAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function implementing the Sentinel's laser attack
+// villsa 09/06/10 implemented
+//
+void A_SentinelAttack(mobj_t* actor)
+{
+ mobj_t* mo;
+ mobj_t* mo2;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t an;
+ int i;
+
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_L_LASER);
+ an = actor->angle >> ANGLETOFINESHIFT;
+
+ if(mo->momy | mo->momx) // villsa - fixed typo (yes, they actually used '|' instead of'||')
+ {
+ for(i = 8; i > 1; i--)
+ {
+ x = mo->x + FixedMul(mobjinfo[MT_L_LASER].radius * i, finecosine[an]);
+ y = mo->y + FixedMul(mobjinfo[MT_L_LASER].radius * i, finesine[an]);
+ z = mo->z + i * (mo->momz >> 2);
+ mo2 = P_SpawnMobj(x, y, z, MT_R_LASER);
+ mo2->target = actor;
+ mo2->momx = mo->momx;
+ mo2->momy = mo->momy;
+ mo2->momz = mo->momz;
+ P_CheckMissileSpawn(mo2);
+ }
+ }
+
+ mo->z += mo->momz >> 2;
+}
+
+//
+// A_StalkerThink
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function to drive Stalker logic.
+//
+void A_StalkerThink(mobj_t* actor)
+{
+ statenum_t statenum;
+
+ if(actor->flags & MF_NOGRAVITY)
+ {
+ if(actor->ceilingz - actor->info->height <= actor->z)
+ return;
+ statenum = S_SPID_11; // 1020
+ }
+ else
+ statenum = S_SPID_18; // 1027
+
+ P_SetMobjState(actor, statenum);
+}
+
+//
+// A_StalkerSetLook
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function to marshall transitions to the
+// Stalker's spawnstate.
+//
+void A_StalkerSetLook(mobj_t* actor)
+{
+ statenum_t statenum;
+
+ if(!actor) // weird; totally unnecessary.
+ return;
+
+ if(actor->flags & MF_NOGRAVITY)
+ {
+ if(actor->state->nextstate == S_SPID_01) // 1010
+ return;
+ statenum = S_SPID_01; // 1010
+ }
+ else
+ {
+ if(actor->state->nextstate == S_SPID_02) // 1011
+ return;
+ statenum = S_SPID_02; // 1011
+ }
+
+ P_SetMobjState(actor, statenum);
+}
+
+//
+// A_StalkerDrop
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Dead simple: removes NOGRAVITY status.
+//
+void A_StalkerDrop(mobj_t* actor)
+{
+ actor->flags &= ~MF_NOGRAVITY;
+}
+
+//
+// A_StalkerScratch
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for Stalker's attack.
+//
+void A_StalkerScratch(mobj_t* actor)
+{
+ if(actor->flags & MF_NOGRAVITY)
+ {
+ // Drop him down before he can attack
+ P_SetMobjState(actor, S_SPID_11); // 1020
+ return;
+ }
+
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+ if(P_CheckMeleeRange(actor))
+ P_DamageMobj(actor->target, actor, actor, 2 * (P_Random() % 8) + 2);
+}
+
+//
+// A_FloatWeave
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function which is responsible for floating
+// actors' constant upward and downward movement. Probably a really bad
+// idea in retrospect given how dodgy the 3D clipping implementation is.
+//
+void A_FloatWeave(mobj_t* actor)
+{
+ fixed_t height;
+ fixed_t z;
+
+ if(actor->threshold)
+ return;
+
+ if(actor->flags & MF_INFLOAT)
+ return;
+
+ height = actor->info->height; // v2
+ z = actor->floorz + 96*FRACUNIT; // v1
+
+ if ( z > actor->ceilingz - height - 16*FRACUNIT )
+ z = actor->ceilingz - height - 16*FRACUNIT;
+
+ if ( z >= actor->z )
+ actor->momz += FRACUNIT;
+ else
+ actor->momz -= FRACUNIT;
+
+ if ( z == actor->z )
+ actor->threshold = 4;
+ else
+ actor->threshold = 8;
+}
+
+//
+// A_RobotMelee
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for Reaver and Templar melee attacks.
+//
+void A_RobotMelee(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+ if(P_CheckMeleeRange(actor))
+ {
+ S_StartSound(actor, sfx_revbld);
+ P_DamageMobj(actor->target, actor, actor, 3 * (P_Random() % 8 + 1));
+ }
+}
+
+//
+// A_TemplarMauler
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Exactly what it sounds like. Kicks your ass.
+//
+void A_TemplarMauler(mobj_t* actor)
+{
+ int i, t;
+ int angle;
+ int bangle;
+ int damage;
+ int slope;
+
+ if(!actor->target)
+ return;
+
+ S_StartSound(actor, sfx_pgrdat);
+ A_FaceTarget(actor);
+ bangle = actor->angle;
+ slope = P_AimLineAttack(actor, bangle, 2048*FRACUNIT);
+
+ for(i = 0; i < 10; i++)
+ {
+ // haleyjd 09/06/10: Very carefully preserved order of P_Random calls
+ damage = (P_Random() & 4) * 2;
+ t = P_Random();
+ angle = bangle + ((t - P_Random()) << 19);
+ t = P_Random();
+ slope = ((t - P_Random()) << 5) + slope;
+ P_LineAttack(actor, angle, 2112*FRACUNIT, slope, damage);
+ }
+}
+
+//
+// A_CrusaderAttack
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action function for the Crusader's Flamethrower.
+// Very similar to the player's flamethrower, seeing how it was ripped
+// off a Crusader by the Rat People ;)
+//
+void A_CrusaderAttack(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ actor->z += (8*FRACUNIT);
+
+ if(P_CheckRobotRange(actor))
+ {
+ A_FaceTarget(actor);
+ actor->angle -= (ANG90 / 8);
+ P_SpawnFacingMissile(actor, actor->target, MT_C_FLAME);
+ }
+ else if(P_CheckMissileRange(actor))
+ {
+ A_FaceTarget(actor);
+ actor->z += (16*FRACUNIT);
+ P_SpawnFacingMissile(actor, actor->target, MT_C_MISSILE);
+
+ actor->angle -= (ANG45 / 32);
+ actor->z -= (16*FRACUNIT);
+ P_SpawnFacingMissile(actor, actor->target, MT_C_MISSILE);
+
+ actor->angle += (ANG45 / 16);
+ P_SpawnFacingMissile(actor, actor->target, MT_C_MISSILE);
+
+ P_SetMobjState(actor, actor->info->seestate);
+ actor->reactiontime += 15;
+ }
+ else
+ P_SetMobjState(actor, actor->info->seestate);
+
+ actor->z -= (8*FRACUNIT);
+}
+
+//
+// A_CrusaderLeft
+//
+// villsa [STRIFE] new codepointer
+//
+void A_CrusaderLeft(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ actor->angle += (ANG90 / 16);
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_C_FLAME);
+ mo->momz = FRACUNIT;
+ mo->z += (16*FRACUNIT);
+
+}
+
+//
+// A_CrusaderRight
+//
+// villsa [STRIFE] new codepointer
+//
+void A_CrusaderRight(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ actor->angle -= (ANG90 / 16);
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_C_FLAME);
+ mo->momz = FRACUNIT;
+ mo->z += (16*FRACUNIT);
+}
+
+//
+// A_CheckTargetVisible2
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Mostly the same as CheckTargetVisible, except without
+// the randomness.
+//
+void A_CheckTargetVisible2(mobj_t* actor)
+{
+ if(!actor->target || actor->target->health <= 0 ||
+ !P_CheckSight(actor, actor->target))
+ {
+ P_SetMobjState(actor, actor->info->seestate);
+ }
+}
+
+//
+// A_InqFlyCheck
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function to check if an Inquisitor wishes
+// to take to flight.
+//
+void A_InqFlyCheck(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+
+ // if not in "robot" range, shoot grenades.
+ if(!P_CheckRobotRange(actor))
+ P_SetMobjState(actor, S_ROB3_14); // 1061
+
+ if(actor->z != actor->target->z)
+ {
+ // Take off all zig!
+ if(actor->z + actor->height + 54*FRACUNIT < actor->ceilingz)
+ P_SetMobjState(actor, S_ROB3_17); // 1064
+ }
+}
+
+//
+// A_InqGrenade
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Inquisitor grenade attack action routine.
+//
+void A_InqGrenade(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+
+ actor->z += MAXRADIUS;
+
+ // grenade 1
+ actor->angle -= (ANG45 / 32);
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_INQGRENADE);
+ mo->momz += (9*FRACUNIT);
+
+ // grenade 2
+ actor->angle += (ANG45 / 16);
+ mo = P_SpawnFacingMissile(actor, actor->target, MT_INQGRENADE);
+ mo->momz += (16*FRACUNIT);
+
+ actor->z -= MAXRADIUS;
+}
+
+//
+// A_InqTakeOff
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Makes an Inquisitor start flying.
+//
+void A_InqTakeOff(mobj_t* actor)
+{
+ angle_t an;
+ fixed_t speed = actor->info->speed * (2 * FRACUNIT / 3);
+ fixed_t dist;
+
+ if(!actor->target)
+ return;
+
+ S_StartSound(actor, sfx_inqjmp);
+
+ actor->z += 64 * FRACUNIT;
+
+ A_FaceTarget(actor);
+
+ an = actor->angle >> ANGLETOFINESHIFT;
+
+ actor->momx = FixedMul(finecosine[an], speed);
+ actor->momy = FixedMul(finesine[an], speed);
+
+ dist = P_AproxDistance(actor->target->x - actor->x,
+ actor->target->y - actor->y);
+
+ dist /= speed;
+ if(dist < 1)
+ dist = 1;
+
+ actor->momz = (actor->target->z - actor->z) / dist;
+ actor->reactiontime = 60;
+ actor->flags |= MF_NOGRAVITY;
+}
+
+//
+// A_InqFly
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Handles an Inquisitor in flight.
+//
+void A_InqFly(mobj_t* actor)
+{
+ if(!(leveltime & 7))
+ S_StartSound(actor, sfx_inqjmp);
+
+ if(--actor->reactiontime < 0 || !actor->momx || !actor->momy ||
+ actor->z <= actor->floorz)
+ {
+ // Come in for a landing.
+ P_SetMobjState(actor, actor->info->seestate);
+ actor->reactiontime = 0;
+ actor->flags &= ~MF_NOGRAVITY;
+ }
+}
+
+//
+// A_FireSigilWeapon
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for the Entity's attack.
+//
+void A_FireSigilWeapon(mobj_t* actor)
+{
+ int choice = P_Random() % 5;
+
+ // STRIFE-TODO: Needs verification. This switch is just weird.
+ switch(choice)
+ {
+ case 0:
+ A_ProgrammerAttack(actor);
+ break;
+ // ain't not seen no case 1, bub...
+ case 2:
+ A_FireSigilEOffshoot(actor);
+ break;
+ case 3:
+ A_SpectreCAttack(actor);
+ break;
+ case 4:
+ A_SpectreDAttack(actor);
+ break;
+ case 5: // BUG: never used? wtf were they thinking?
+ A_SpectreEAttack(actor);
+ break;
+ default:
+ break;
+ }
+}
+
+//
+// A_ProgrammerAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for the Programmer's main
+// attack; equivalent to the player's first Sigil.
+//
+void A_ProgrammerAttack(mobj_t* actor)
+{
+ mobj_t *mo;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMobj(actor->target->x, actor->target->y, ONFLOORZ,
+ MT_SIGIL_A_GROUND);
+ mo->threshold = 25;
+ mo->target = actor;
+ mo->health = -2;
+ mo->tracer = actor->target;
+}
+
+//
+// A_Sigil_A_Action
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Called by MT_SIGIL_A_GROUND to zot anyone nearby with
+// corny looking lightning bolts.
+//
+void A_Sigil_A_Action(mobj_t* actor)
+{
+ int t, x, y, type;
+ mobj_t *mo;
+
+ if(actor->threshold)
+ actor->threshold--;
+
+ t = P_Random();
+ actor->momx += ((t & 3) - (P_Random() & 3)) << FRACBITS;
+ t = P_Random();
+ actor->momy += ((t & 3) - (P_Random() & 3)) << FRACBITS;
+
+ t = P_Random();
+ x = 50*FRACUNIT * ((t & 3) - (P_Random() & 3)) + actor->x;
+ t = P_Random();
+ y = 50*FRACUNIT * ((t & 3) - (P_Random() & 3)) + actor->y;
+
+ if(actor->threshold <= 25)
+ type = MT_SIGIL_A_ZAP_LEFT;
+ else
+ type = MT_SIGIL_A_ZAP_RIGHT;
+
+ mo = P_SpawnMobj(x, y, ONCEILINGZ, type);
+ mo->momz = -18 * FRACUNIT;
+ mo->target = actor->target;
+ mo->health = actor->health;
+
+ mo = P_SpawnMobj(actor->x, actor->y, ONCEILINGZ, MT_SIGIL_A_ZAP_RIGHT);
+ mo->momz = -18 * FRACUNIT;
+ mo->target = actor->target;
+ mo->health = actor->health;
+}
+
+//
+// A_SpectreEAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for the Loremaster's Spectre.
+// Equivalent to the player's final Sigil attack.
+//
+void A_SpectreEAttack(mobj_t* actor)
+{
+ mobj_t *mo;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_SIGIL_SE_SHOT);
+ mo->health = -2;
+}
+
+//
+// A_SpectreCAttack
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action routine for the Oracle's Spectre. Equivalent to the player's
+// third Sigil attack.
+//
+void A_SpectreCAttack(mobj_t* actor)
+{
+ mobj_t* mo;
+ int i;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + (32*FRACUNIT), MT_SIGIL_A_ZAP_RIGHT);
+ mo->momz = -(18*FRACUNIT);
+ mo->target = actor;
+ mo->health = -2;
+ mo->tracer = actor->target;
+
+ actor->angle -= ANG90;
+ for(i = 0; i < 20; i++)
+ {
+ actor->angle += (ANG90 / 10);
+ mo = P_SpawnMortar(actor, MT_SIGIL_C_SHOT);
+ mo->health = -2;
+ mo->z = actor->z + (32*FRACUNIT);
+ }
+ actor->angle -= ANG90;
+}
+
+//
+// A_AlertSpectreC
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function called by the Oracle when it is
+// killed. Finds an MT_SPECTRE_C anywhere on the map and awakens it.
+//
+void A_AlertSpectreC(mobj_t* actor)
+{
+ thinker_t *th;
+
+ for(th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if(th->function.acp1 == (actionf_p1)P_MobjThinker)
+ {
+ mobj_t *mo = (mobj_t *)th;
+
+ if(mo->type == MT_SPECTRE_C)
+ {
+ P_SetMobjState(mo, mo->info->seestate);
+ mo->target = actor->target;
+ return;
+ }
+ }
+ }
+}
+
+//
+// A_Sigil_E_Action
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action routine for Sigil "E" shots. Spawns the room-filling
+// lightning bolts that seem to often do almost nothing.
+//
+void A_Sigil_E_Action(mobj_t* actor)
+{
+ actor->angle += ANG90;
+ P_SpawnMortar(actor, MT_SIGIL_E_OFFSHOOT);
+
+ actor->angle -= ANG180;
+ P_SpawnMortar(actor, MT_SIGIL_E_OFFSHOOT);
+
+ actor->angle += ANG90;
+ P_SpawnMortar(actor, MT_SIGIL_E_OFFSHOOT);
+
+}
+
+//
+// A_SigilTrail
+//
+// villsa [STRIFE] new codepointer
+//
+void A_SigilTrail(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x - actor->momx,
+ actor->y - actor->momy,
+ actor->z, MT_SIGIL_TRAIL);
+
+ mo->angle = actor->angle;
+ mo->health = actor->health;
+
+}
+
+//
+// A_SpectreDAttack
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function for Macil's Spectre.
+// Equivalent of the player's fourth Sigil attack.
+//
+void A_SpectreDAttack(mobj_t* actor)
+{
+ mobj_t *mo;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_SIGIL_SD_SHOT);
+ mo->health = -2;
+ mo->tracer = actor->target;
+}
+
+//
+// A_FireSigilEOffshoot
+//
+// [STRIFE] New function
+// haleyjd 09/06/10: Action function to fire part of a Sigil E
+// attack. Used at least by the Entity.
+//
+void A_FireSigilEOffshoot(mobj_t* actor)
+{
+ mobj_t *mo;
+
+ if(!actor->target)
+ return;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_SIGIL_E_OFFSHOOT);
+ mo->health = -2;
+}
+
+//
+// A_ShadowOff
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Disables SHADOW and MVIS flags.
+//
+void A_ShadowOff(mobj_t* actor)
+{
+ actor->flags &= ~(MF_SHADOW|MF_MVIS);
+}
+
+//
+// A_ModifyVisibility
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Turns on SHADOW, and turns off MVIS.
+//
+void A_ModifyVisibility(mobj_t* actor)
+{
+ actor->flags |= MF_SHADOW;
+ actor->flags &= ~MF_MVIS;
+}
+
+//
+// A_ShadowOn
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Turns on SHADOW and MVIS.
+//
+void A_ShadowOn(mobj_t* actor)
+{
+ actor->flags |= (MF_SHADOW|MF_MVIS);
+}
+
+//
+// A_SetTLOptions
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Sets SHADOW and/or MVIS based on the thing's spawnpoint options.
+//
+void A_SetTLOptions(mobj_t* actor)
+{
+ if(actor->spawnpoint.options & MTF_TRANSLUCENT)
+ actor->flags |= MF_SHADOW;
+ if(actor->spawnpoint.options & MTF_MVIS)
+ actor->flags |= MF_MVIS;
+}
+
+//
+// A_BossMeleeAtk
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Gratuitous melee attack used by multiple boss characters,
+// just for the sake of having one. It's not like anybody in their right
+// mind would get close to any of the maniacs that use this ;)
+//
+void A_BossMeleeAtk(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ P_DamageMobj(actor->target, actor, actor, 10 * (P_Random() & 9));
+}
+
+//
+// A_BishopAttack
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Bishop's homing missile attack.
+//
+void A_BishopAttack(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ if(!actor->target)
+ return;
+
+ actor->z += MAXRADIUS;
+
+ mo = P_SpawnMissile(actor, actor->target, MT_SEEKMISSILE);
+ mo->tracer = actor->target;
+
+ actor->z -= MAXRADIUS;
+}
+
+//
+// A_FireHookShot
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action function for the Loremaster's hookshot attack.
+//
+void A_FireHookShot(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ P_SpawnMissile(actor, actor->target, MT_HOOKSHOT);
+}
+
+//
+// A_FireChainShot
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Action function for the hookshot projectile. Spawns echoes
+// to create a chain-like appearance.
+//
+void A_FireChainShot(mobj_t* actor)
+{
+ S_StartSound(actor, sfx_tend);
+
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_CHAINSHOT); // haleyjd: fixed type
+
+ P_SpawnMobj(actor->x - (actor->momx >> 1),
+ actor->y - (actor->momy >> 1),
+ actor->z, MT_CHAINSHOT);
+
+ P_SpawnMobj(actor->x - actor->momx,
+ actor->y - actor->momy,
+ actor->z, MT_CHAINSHOT);
+}
+
+//
+// A_MissileSmoke
+//
+// villsa [STRIFE] new codepointer
+//
+void A_MissileSmoke(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ S_StartSound(actor, sfx_rflite);
+ P_SpawnPuff(actor->x, actor->y, actor->z);
+ mo = P_SpawnMobj(actor->x - actor->momx,
+ actor->y - actor->momy,
+ actor->z, MT_MISSILESMOKE);
+
+ mo->momz = FRACUNIT;
+}
+
+//
+// A_SpawnSparkPuff
+//
+// villsa [STRIFE] new codepointer
+//
+void A_SpawnSparkPuff(mobj_t* actor)
+{
+ int r;
+ mobj_t* mo;
+ fixed_t x;
+ fixed_t y;
+
+ r = P_Random();
+ x = (10*FRACUNIT) * ((r & 3) - (P_Random() & 3)) + actor->x;
+ r = P_Random();
+ y = (10*FRACUNIT) * ((r & 3) - (P_Random() & 3)) + actor->y;
+
+ mo = P_SpawnMobj(x, y, actor->z, MT_SPARKPUFF);
+ P_SetMobjState(mo, S_BNG4_01); // 199
+ mo->momz = FRACUNIT;
+}
+
+
+// haleyjd 09/05/10: [STRIFE] Removed:
+// A_PosAttack, A_SPosAttack, A_CPosAttack, A_CPosRefire, A_SpidRefire,
+// A_BspiAttack, A_TroopAttack, A_SargAttack, A_HeadAttack, A_CyberAttack,
+// A_BruisAttack, A_SkelMissile
+
+
+int TRACEANGLE = 0xE000000; // villsa [STRIFE] changed from 0xC000000 to 0xE000000
+
+//
+// A_Tracer
+//
+void A_Tracer (mobj_t* actor)
+{
+ angle_t exact;
+ fixed_t dist;
+ fixed_t slope;
+ mobj_t* dest;
+ //mobj_t* th;
+
+ // villsa [STRIFE] removed all randomization and puff code
+
+ // 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)
+ {
+ // villsa [STRIFE] slightly different algorithm
+ 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;
+}
+
+//
+// A_ProgrammerMelee
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Melee attack for the Programmer.
+// haleyjd - fixed damage formula
+//
+void A_ProgrammerMelee(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ A_FaceTarget(actor);
+ if(P_CheckMeleeRange(actor))
+ {
+ int damage = 8 * (P_Random() % 10 + 1);
+
+ S_StartSound(actor, sfx_mtalht);
+ P_DamageMobj(actor->target, actor, actor, damage);
+ }
+
+}
+
+// haleyjd 09/05/10: [STRIFE] Removed:
+// A_SkelWhoosh, A_SkelFist, PIT_VileCheck, A_VileChase, A_VileStart,
+// A_StartFire, A_FireCrackle, A_Fire, A_VileTarget, A_VileAttack
+// A_FatRaise, A_FatAttack1, A_FatAttack2, A_FatAttack3, A_SkullAttack,
+// A_PainShootSkull, A_PainAttack, A_PainDie
+
+//
+// A_Scream
+//
+// villsa [STRIFE]
+// * Has no random death sounds, so play deathsound directly
+// * Full-volume roars for the Entity and Inquisitor.
+//
+void A_Scream(mobj_t* actor)
+{
+ if(!actor->info->deathsound)
+ return;
+
+ // Check for bosses.
+ if(actor->type == MT_ENTITY || actor->type == MT_INQUISITOR)
+ S_StartSound(NULL, actor->info->deathsound); // full volume
+ else
+ S_StartSound(actor, actor->info->deathsound);
+}
+
+//
+// A_XScream
+//
+// villsa [STRIFE]
+// * Robots will play deathsound while non-robots play the slop sfx
+//
+void A_XScream(mobj_t* actor)
+{
+ int sound;
+
+ if(actor->flags & MF_NOBLOOD && actor->info->deathsound)
+ sound = actor->info->deathsound;
+ else
+ sound = sfx_slop;
+
+ S_StartSound(actor, sound);
+}
+
+//
+// A_Pain
+//
+// villsa [STRIFE]
+// * Play random peasant sounds; otherwise play painsound directly
+//
+void A_Pain(mobj_t* actor)
+{
+ int sound = actor->info->painsound;
+
+ if(sound)
+ {
+ if(sound >= sfx_pespna && sound <= sfx_pespnd)
+ sound = sfx_pespna + (P_Random() % 4);
+
+ S_StartSound(actor, sound);
+ }
+}
+
+//
+// A_PeasantCrash
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Called from Peasant's "crash" state (not to be confused with
+// Heretic crash states), which is invoked when the Peasant has taken
+// critical but sub-fatal damage. It will "bleed out" the rest of its
+// health by calling this function repeatedly.
+//
+void A_PeasantCrash(mobj_t* actor)
+{
+ // Set NODIALOG, because you probably wouldn't feel like talking either
+ // if somebody just stabbed you in the gut with a punch dagger...
+ actor->flags |= MF_NODIALOG;
+
+ if(!(P_Random() % 5))
+ {
+ A_Pain(actor); // inlined in asm
+ actor->health--;
+ }
+
+ if(actor->health <= 0)
+ P_KillMobj(actor->target, actor);
+}
+
+//
+// A_Fall
+//
+// [STRIFE]
+// * Set NODIALOG, and clear NOGRAVITY and SHADOW
+//
+void A_Fall (mobj_t *actor)
+{
+ // villsa [STRIFE] set NODIALOG flag to stop dialog
+ actor->flags |= MF_NODIALOG;
+
+ // actor is on ground, it can be walked over
+ // villsa [STRIFE] remove nogravity/shadow flags as well
+ actor->flags &= ~(MF_SOLID|MF_NOGRAVITY|MF_SHADOW);
+}
+
+//
+// A_HideZombie
+//
+// villsa [STRIFE] new codepointer
+// Used by the "Becoming" Acolytes on the Loremaster's level.
+//
+void A_HideZombie(mobj_t* actor)
+{
+ line_t junk;
+
+ junk.tag = 999;
+ EV_DoDoor(&junk, blazeClose);
+
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_MerchantPain
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Pain pointer for merchant characters. They close up shop for
+// a while and set off the alarm.
+//
+void A_MerchantPain(mobj_t* actor)
+{
+ line_t junk;
+
+ junk.tag = 999;
+ EV_DoDoor(&junk, shopClose);
+
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+// haleyjd 09/05/10: Removed unused CheckBossEnd Choco routine.
+
+// haleyjd 09/05/10: [STRIFE] Removed:
+// A_Hoof, A_Metal, A_BabyMetal, A_OpenShotgun2, A_LoadShotgun2,
+// A_CloseShotgun2, A_BrainAwake, A_BrainPain, A_BrainScream, A_BrainExplode,
+// A_BrainDie, A_BrainSpit, A_SpawnSound, A_SpawnFly
+
+//
+// A_ProgrammerDie
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Action routine for the Programmer's grisly death. Spawns the
+// separate mechanical base object and sends it flying off in some random
+// direction.
+//
+void A_ProgrammerDie(mobj_t* actor)
+{
+ int r;
+ angle_t an;
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 24*FRACUNIT, MT_PROGRAMMERBASE);
+
+ // haleyjd 20110223: fix add w/ANG180
+ r = P_Random();
+ an = ((r - P_Random()) << 22) + actor->angle + ANG180;
+ mo->angle = an;
+
+ P_ThrustMobj(mo, an, mo->info->speed); // inlined in asm
+
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_InqTossArm
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Inquisitor death action. Spawns an arm and tosses it.
+//
+void A_InqTossArm(mobj_t* actor)
+{
+ int r;
+ angle_t an;
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + (24*FRACUNIT), MT_INQARM);
+
+ r = P_Random();
+ an = ((r - P_Random()) << 22) + actor->angle - ANG90;
+ mo->angle = an;
+
+ P_ThrustMobj(mo, an, mo->info->speed); // inlined in asm
+
+ mo->momz = P_Random() << 10;
+}
+
+//
+// A_SpawnSpectreA
+//
+// villsa [STRIFE] new codepointer (unused)
+// 09/08/10: Spawns Spectre A. Or would, if anything actually used this.
+// This is evidence that the Programmer's spectre, which appears in the
+// Catacombs in the final version, was originally meant to be spawned
+// after his death.
+//
+void A_SpawnSpectreA(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_A);
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_SpawnSpectreB
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Action function to spawn the Bishop's spectre.
+//
+void A_SpawnSpectreB(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_B);
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_SpawnSpectreC
+//
+// villsa [STRIFE] new codepointer (unused)
+// 09/08/10: Action function to spawn the Oracle's spectre. Also
+// unused, because the Oracle's spectre is already present on the
+// map and is awakened on his death. Also left over from the
+// unreleased beta (and demo) versions.
+//
+void A_SpawnSpectreC(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_C);
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_SpawnSpectreD
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Action function to spawn Macil's Spectre.
+//
+void A_SpawnSpectreD(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_D);
+ mo->momz = P_Random() << 9;
+}
+
+//
+// A_SpawnSpectreE
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Action function to spawn the Loremaster's Spectre.
+//
+void A_SpawnSpectreE(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPECTRE_E);
+ mo->momz = P_Random() << 9;
+}
+
+// [STRIFE] New statics - Remember the Entity's spawning position.
+static fixed_t entity_pos_x = 0;
+static fixed_t entity_pos_y = 0;
+static fixed_t entity_pos_z = 0;
+
+//
+// A_SpawnEntity
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: You will fall on your knees before the True God, the One Light.
+//
+void A_SpawnEntity(mobj_t* actor)
+{
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 70*FRACUNIT, MT_ENTITY);
+ mo->momz = 5*FRACUNIT;
+
+ entity_pos_x = mo->x;
+ entity_pos_y = mo->y;
+ entity_pos_z = mo->z;
+}
+
+//
+// P_ThrustMobj
+//
+// villsa [STRIFE] new function
+// Thrusts an thing in a specified force/direction
+// Beware! This is inlined everywhere in the asm
+//
+void P_ThrustMobj(mobj_t *actor, angle_t angle, fixed_t force)
+{
+ angle_t an = angle >> ANGLETOFINESHIFT;
+ actor->momx += FixedMul(finecosine[an], force);
+ actor->momy += FixedMul(finesine[an], force);
+}
+
+//
+// A_EntityDeath
+//
+// [STRIFE]
+// haleyjd 09/08/10: The death of the Entity's spectre brings forth
+// three subentities, which are significantly less dangerous on their
+// own but threatening together.
+//
+void A_EntityDeath(mobj_t* actor)
+{
+ mobj_t *subentity;
+ angle_t an;
+ fixed_t dist;
+
+ dist = 2 * mobjinfo[MT_SUBENTITY].radius;
+
+ // Subentity One
+ an = actor->angle >> ANGLETOFINESHIFT;
+ subentity = P_SpawnMobj(FixedMul(finecosine[an], dist) + entity_pos_x,
+ FixedMul(finesine[an], dist) + entity_pos_y,
+ entity_pos_z, MT_SUBENTITY);
+ subentity->target = actor->target;
+ A_FaceTarget(subentity);
+ P_ThrustMobj(subentity, subentity->angle, 625 << 13);
+
+ // Subentity Two
+ an = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
+ subentity = P_SpawnMobj(FixedMul(finecosine[an], dist) + entity_pos_x,
+ FixedMul(finesine[an], dist) + entity_pos_y,
+ entity_pos_z, MT_SUBENTITY);
+ subentity->target = actor->target;
+ P_ThrustMobj(subentity, actor->angle + ANG90, 4);
+ A_FaceTarget(subentity);
+
+ // Subentity Three
+ an = (actor->angle - ANG90) >> ANGLETOFINESHIFT;
+ subentity = P_SpawnMobj(FixedMul(finecosine[an], dist) + entity_pos_x,
+ FixedMul(finesine[an], dist) + entity_pos_y,
+ entity_pos_z, MT_SUBENTITY);
+ subentity->target = actor->target;
+ P_ThrustMobj(subentity, actor->angle - ANG90, 4);
+ A_FaceTarget(subentity);
+}
+
+//
+// A_SpawnZombie
+//
+// villsa [STRIFE] new codepointer
+//
+void A_SpawnZombie(mobj_t* actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_ZOMBIE);
+}
+
+//
+// A_ZombieInSpecialSector
+//
+// villsa [STRIFE] new codepointer
+//
+void A_ZombieInSpecialSector(mobj_t* actor)
+{
+ sector_t* sector;
+ fixed_t force;
+ angle_t angle;
+ int tagval;
+
+ sector = actor->subsector->sector;
+ if(actor->z != sector->floorheight)
+ return;
+
+ if(sector->special <= 15)
+ P_DamageMobj(actor, NULL, NULL, 999);
+ else if(sector->special == 18)
+ {
+ tagval = sector->tag - 100;
+ force = (tagval % 10) << 12;
+ angle = (tagval / 10) << 29;
+ P_ThrustMobj(actor, angle, force); // inlined in asm
+ }
+}
+
+//
+// A_CrystalExplode
+//
+// villsa [STRIFE] new codepointer
+// Throws out debris from the Power Crystal and sets its sector floorheight
+// to the lowest surrounding floor (this is maybe the only time a direct
+// level-changing action is done by an object in this fashion in any of
+// the DOOM engine games... they usually call a line special instead)
+//
+void A_CrystalExplode(mobj_t* actor)
+{
+ sector_t* sector;
+ mobj_t* rubble;
+ int i;
+ int r;
+
+ sector = actor->subsector->sector;
+ sector->lightlevel = 0;
+ sector->floorheight = P_FindLowestFloorSurrounding(sector);
+
+ // spawn rubble
+ for(i = 0; i < 8; i++)
+ {
+ rubble = P_SpawnMobj(actor->x, actor->y, actor->z, MT_RUBBLE1 + i);
+ r = P_Random();
+ rubble->momx = ((r & 0x0f) - (P_Random() & 7)) << FRACBITS;
+ r = P_Random();
+ rubble->momy = ((r & 7) - (P_Random() & 7)) << FRACBITS;
+ rubble->momz = ((P_Random() & 3) << FRACBITS) + (7*FRACUNIT);
+ }
+}
+
+// [STRIFE] New static global - buffer used for various player messages.
+static char pmsgbuffer[80];
+
+//
+// P_FreePrisoners
+//
+// haleyjd 09/08/10: [STRIFE] New function
+// * Called when the prisoners get freed, obviously. Gives a
+// message and awards quest token 13.
+//
+void P_FreePrisoners(void)
+{
+ int i;
+
+ DEH_snprintf(pmsgbuffer, sizeof(pmsgbuffer), "You've freed the prisoners!");
+
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_QUEST13);
+ players[i].message = pmsgbuffer;
+ }
+}
+
+//
+// P_DestroyConverter
+//
+// haleyjd 09/08/10: [STRIFE] New function
+// * Called when the converter is shut down in the factory.
+// Gives several items and a message.
+//
+void P_DestroyConverter(void)
+{
+ int i;
+
+ DEH_snprintf(pmsgbuffer, sizeof(pmsgbuffer), "You've destroyed the Converter!");
+
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_QUEST25);
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ players[i].message = pmsgbuffer;
+ }
+}
+
+//
+// A_QuestMsg
+//
+// villsa [STRIFE] new codepointer
+// Displays text based on quest item's name
+// Quest item is based on actor's speed
+//
+void A_QuestMsg(mobj_t* actor)
+{
+ char* name;
+ int quest;
+ int i;
+
+ // get name
+ name = DEH_String(mobjinfo[(MT_TOKEN_QUEST1 - 1) + actor->info->speed].name);
+ strcpy(pmsgbuffer, name); // inlined in asm
+
+ // give quest and display message to players
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ quest = 1 << (actor->info->speed - 1);
+ players[i].message = pmsgbuffer;
+ players[i].questflags |= quest;
+ }
+}
+
+//
+// A_ExtraLightOff
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Called by the Power Crystal to turn off the extended
+// flash of light caused by its explosion.
+//
+void A_ExtraLightOff(mobj_t* actor)
+{
+ if(!actor->target)
+ return;
+
+ if(!actor->target->player)
+ return;
+
+ actor->target->player->extralight = 0;
+}
+
+//
+// A_CrystalRadiusAtk
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Called by the power crystal when it dies.
+//
+void A_CrystalRadiusAtk(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 512);
+
+ if(!(actor->target && actor->target->player))
+ return;
+
+ // set extralight to 5 for near full-bright
+ actor->target->player->extralight = 5;
+}
+
+//
+// A_DeathExplode5
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DeathExplode5(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 192);
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_DeathExplode1
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DeathExplode1(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 128);
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_DeathExplode2
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DeathExplode2(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 64);
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_DeathExplode3
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DeathExplode3(mobj_t* actor)
+{
+ P_RadiusAttack(actor, actor->target, 32);
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_RaiseAlarm
+//
+// villsa [STRIFE] new codepointer
+// 09/08/10: Set off the infamous alarm. This is just a noise alert.
+//
+void A_RaiseAlarm(mobj_t* actor)
+{
+ if(actor->target && actor->target->player)
+ P_NoiseAlert(actor->target, actor); // inlined in asm
+}
+
+//
+// A_MissileTick
+// villsa [STRIFE] - new codepointer
+//
+void A_MissileTick(mobj_t* actor)
+{
+ if(--actor->reactiontime <= 0)
+ {
+ P_ExplodeMissile(actor);
+ actor->flags &= ~MF_MISSILE;
+ }
+}
+
+//
+// A_SpawnGrenadeFire
+// villsa [STRIFE] - new codepointer
+//
+void A_SpawnGrenadeFire(mobj_t* actor)
+{
+ P_SpawnMobj(actor->x, actor->y, actor->z, MT_PFLAME);
+}
+
+//
+// A_NodeChunk
+//
+// villsa [STRIFE] - new codepointer
+// Throw out "nodes" from a spectral entity
+//
+void A_NodeChunk(mobj_t* actor)
+{
+ int r;
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 10*FRACUNIT, MT_NODE);
+ r = P_Random();
+ mo->momx = ((r & 0x0f) - (P_Random() & 7)) << FRACBITS;
+ r = P_Random();
+ mo->momy = ((r & 7) - (P_Random() & 0x0f)) << FRACBITS;
+ mo->momz = (P_Random() & 0x0f) << FRACBITS;
+}
+
+//
+// A_HeadChunk
+//
+// villsa [STRIFE] - new codepointer
+// Throw out the little "eye"-like object from a spectral entity when it dies.
+//
+void A_HeadChunk(mobj_t* actor)
+{
+ int r;
+ mobj_t* mo;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + 10*FRACUNIT, MT_SPECTREHEAD);
+ r = P_Random();
+ mo->momx = ((r & 7) - (P_Random() & 0x0f)) << FRACBITS;
+ r = P_Random();
+ mo->momy = ((r & 0x0f) - (P_Random() & 7)) << FRACBITS;
+ mo->momz = (P_Random() & 7) << FRACBITS;
+}
+
+//
+// A_BurnSpread
+// villsa [STRIFE] - new codepointer
+//
+void A_BurnSpread(mobj_t* actor)
+{
+ int t;
+ mobj_t* mo;
+ fixed_t x;
+ fixed_t y;
+
+ actor->momz -= (8*FRACUNIT);
+
+ t = P_Random();
+ actor->momx += ((t & 3) - (P_Random() & 3)) << FRACBITS;
+ t = P_Random();
+ actor->momy += ((t & 3) - (P_Random() & 3)) << FRACBITS;
+
+ S_StartSound(actor, sfx_lgfire);
+
+ if(actor->flags & MF_DROPPED)
+ return; // not the parent
+
+ // haleyjd 20110223: match order of calls in binary
+ y = actor->y + (((P_Random() + 12) & 31) << FRACBITS);
+ x = actor->x + (((P_Random() + 12) & 31) << FRACBITS);
+
+ // spawn child
+ mo = P_SpawnMobj(x, y, actor->z + (4*FRACUNIT), MT_PFLAME);
+
+ t = P_Random();
+ mo->momx += ((t & 7) - (P_Random() & 7)) << FRACBITS;
+ t = P_Random();
+ mo->momy += ((t & 7) - (P_Random() & 7)) << FRACBITS;
+ mo->momz -= FRACUNIT;
+ mo->flags |= MF_DROPPED;
+ mo->reactiontime = (P_Random() & 3) + 2;
+}
+
+//
+// A_BossDeath
+//
+// Possibly trigger special effects
+// if on first boss level
+//
+// haleyjd 09/17/10: [STRIFE]
+// * Modified to handle all Strife bosses.
+//
+void A_BossDeath (mobj_t* actor)
+{
+ int i;
+ thinker_t *th;
+ line_t junk;
+
+ // only the following types can be a boss:
+ switch(actor->type)
+ {
+ case MT_CRUSADER:
+ case MT_SPECTRE_A:
+ case MT_SPECTRE_B:
+ case MT_SPECTRE_C:
+ case MT_SPECTRE_D:
+ case MT_SPECTRE_E:
+ case MT_SUBENTITY:
+ case MT_PROGRAMMER:
+ break;
+ default:
+ return;
+ }
+
+ // check for a living player
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ if(playeringame[i] && players[i].health > 0)
+ break;
+ }
+ if(i == MAXPLAYERS)
+ return; // everybody's dead.
+
+ // check for a still living boss
+ for(th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if(th->function.acp1 == (actionf_p1) P_MobjThinker)
+ {
+ mobj_t *mo = (mobj_t *)th;
+
+ if(mo != actor && mo->type == actor->type && mo->health > 0)
+ return; // one is still alive.
+ }
+ }
+
+ // Victory!
+ switch(actor->type)
+ {
+ case MT_CRUSADER:
+ junk.tag = 667;
+ EV_DoFloor(&junk, lowerFloorToLowest);
+ break;
+
+ case MT_SPECTRE_A:
+ GiveVoiceObjective("VOC95", "LOG95", 0);
+ junk.tag = 999;
+ EV_DoFloor(&junk, lowerFloorToLowest);
+ break;
+
+ case MT_SPECTRE_B:
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_BISHOP);
+ GiveVoiceObjective("VOC74", "LOG74", 0);
+ break;
+
+ case MT_SPECTRE_C:
+ // Look for an MT_ORACLE - this is for in case the player awakened the
+ // Oracle's spectre without killing the Oracle, which is possible by
+ // looking up to max and firing the Sigil at it. If this were not done,
+ // a serious sequence break possibility would arise where one could
+ // kill both the Oracle AND Macil, possibly throwing the game out of
+ // sorts entirely. Too bad they thought of it ;) However this also
+ // causes a bug sometimes! The Oracle, in its death state, sets the
+ // Spectre C back to its seestate. If the Spectre C is already dead,
+ // it becomes an undead ghost monster. Then it's a REAL spectre ;)
+ for(th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if(th->function.acp1 == (actionf_p1) P_MobjThinker)
+ {
+ mobj_t *mo = (mobj_t *)th;
+
+ // KILL ALL ORACLES! RAWWR!
+ if(mo != actor && mo->type == MT_ORACLE && mo->health > 0)
+ P_KillMobj(actor, mo);
+ }
+ }
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_ORACLE);
+
+ // Bishop is dead? - verify.
+ if(players[0].questflags & QF_QUEST21)
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_QUEST22);
+
+ // Macil is dead?
+ if(players[0].questflags & QF_QUEST24)
+ {
+ // Loremaster is dead?
+ if(players[0].questflags & QF_QUEST26)
+ {
+ // We wield the complete sigil, blahblah
+ GiveVoiceObjective("VOC85", "LOG85", 0);
+ }
+ }
+ else
+ {
+ // So much for prognostication!
+ GiveVoiceObjective("VOC87", "LOG87", 0);
+ }
+ junk.tag = 222; // Open the exit door again;
+ EV_DoDoor(&junk, open); // Note this is NOT the Loremaster door...
+ break;
+
+ case MT_SPECTRE_D:
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_MACIL);
+ if(players[0].questflags & QF_QUEST25) // Destroyed converter?
+ GiveVoiceObjective("VOC106", "LOG106", 0);
+ else
+ GiveVoiceObjective("VOC79", "LOG79", 0);
+ break;
+
+ case MT_SPECTRE_E:
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_LOREMASTER);
+ if(!netgame)
+ {
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(&players[0], SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ }
+ if(players[0].sigiltype == 4)
+ GiveVoiceObjective("VOC85", "LOG85", 0);
+ else
+ GiveVoiceObjective("VOC83", "LOG83", 0);
+ junk.tag = 666;
+ EV_DoFloor(&junk, lowerFloorToLowest);
+ break;
+
+ case MT_SUBENTITY:
+ F_StartFinale();
+ break;
+
+ case MT_PROGRAMMER:
+ F_StartFinale();
+ G_ExitLevel(0);
+ break;
+
+ default:
+ // Real classy, Rogue.
+ if(actor->type)
+ I_Error("Error: Unconnected BossDeath id %d", actor->type);
+ break;
+ }
+}
+
+//
+// A_AcolyteSpecial
+//
+// villsa [STRIFE] - new codepointer
+// Awards quest #7 when all the Blue Acolytes are killed in Tarnhill
+//
+void A_AcolyteSpecial(mobj_t* actor)
+{
+ int i;
+ thinker_t* th;
+
+ if(actor->type != MT_GUARD8)
+ return; // must be MT_GUARD8
+
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ if(playeringame[i] && players[i].health > 0)
+ break;
+ }
+
+ if(i == 8)
+ return;
+
+ for(th = thinkercap.next; th != &thinkercap; th = th->next)
+ {
+ if(th->function.acp1 == (actionf_p1) P_MobjThinker)
+ {
+ mobj_t *mo = (mobj_t *)th;
+
+ // Found a living MT_GUARD8?
+ if(mo != actor && mo->type == actor->type && mo->health > 0)
+ return;
+ }
+ }
+
+ // All MT_GUARD8 are dead, give quest token #7 to all players
+ for(i = 0; i < MAXPLAYERS; i++)
+ P_GiveItemToPlayer(&players[i], SPR_TOKN, MT_TOKEN_QUEST7);
+
+ // play voice, give objective
+ GiveVoiceObjective("VOC14", "LOG14", 0);
+}
+
+//
+// A_InqChase
+// villsa [STRIFE] - new codepointer
+//
+void A_InqChase(mobj_t* actor)
+{
+ S_StartSound(actor, sfx_inqact);
+ A_Chase(actor);
+}
+
+//
+// A_StalkerChase
+// villsa [STRIFE] - new codepointer
+//
+void A_StalkerChase(mobj_t* actor)
+{
+ S_StartSound(actor, sfx_spdwlk);
+ A_Chase(actor);
+}
+
+//
+// A_PlayerScream
+//
+// [STRIFE]
+// * Modified to eliminate gamemode check and to use Strife sound.
+//
+void A_PlayerScream (mobj_t* mo)
+{
+ // Default death sound.
+ int sound = sfx_pldeth;
+
+ // villsa [STRIFE] don't check for gamemode
+ if(mo->health < -50)
+ {
+ // IF THE PLAYER DIES
+ // LESS THAN -50% WITHOUT GIBBING
+ sound = sfx_plxdth; // villsa [STRIFE] different sound
+ }
+
+ S_StartSound (mo, sound);
+}
+
+//
+// A_TeleportBeacon
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_TeleportBeacon(mobj_t* actor)
+{
+ mobj_t* mobj;
+ mobj_t* fog;
+ fixed_t fog_x;
+ fixed_t fog_y;
+
+ if(actor->target != players[actor->miscdata].mo)
+ actor->target = players[actor->miscdata].mo;
+
+ mobj = P_SpawnMobj(actor->x, actor->y, ONFLOORZ, MT_REBEL1);
+
+ if(!P_TryMove(mobj, mobj->x, mobj->y))
+ {
+ // Rebel is probably stuck in something.. too bad
+ P_RemoveMobj(mobj);
+ return;
+ }
+
+ // beacon no longer solid
+ actor->flags &= ~MF_SOLID;
+
+ // set color and flags
+ mobj->flags |= ((actor->miscdata << MF_TRANSSHIFT) | MF_NODIALOG);
+ mobj->target = NULL;
+
+ // double Rebel's health in deathmatch mode
+ if(deathmatch)
+ mobj->health <<= 1;
+
+ if(actor->target)
+ {
+ mobj_t* targ = actor->target->target;
+
+ if(targ)
+ {
+ if(targ->type != MT_REBEL1 || targ->miscdata != mobj->miscdata)
+ mobj->target = targ;
+ }
+ }
+
+ P_SetMobjState(mobj, mobj->info->seestate);
+ mobj->angle = actor->angle;
+
+ fog_x = mobj->x + FixedMul(20*FRACUNIT, finecosine[actor->angle>>ANGLETOFINESHIFT]);
+ fog_y = mobj->y + FixedMul(20*FRACUNIT, finesine[actor->angle>>ANGLETOFINESHIFT]);
+
+ fog = P_SpawnMobj(fog_x, fog_y, mobj->z, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+
+ if(--actor->health < 0)
+ P_RemoveMobj(actor);
+}
+
+//
+// A_BodyParts
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Spawns gibs when organic actors get splattered, or junk
+// when robots explode.
+//
+void A_BodyParts(mobj_t* actor)
+{
+ mobjtype_t type;
+ mobj_t* mo;
+ angle_t an;
+
+ if(actor->flags & MF_NOBLOOD) // Robots are flagged NOBLOOD
+ type = MT_JUNK;
+ else
+ type = MT_MEAT;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + (24*FRACUNIT), type);
+ P_SetMobjState(mo, mo->info->spawnstate + (P_Random() % 19));
+
+ an = (P_Random() << 13) / 255;
+ mo->angle = an << ANGLETOFINESHIFT;
+
+ mo->momx = FixedMul(finecosine[an], (P_Random() & 0x0f) << FRACBITS);
+ mo->momy = FixedMul(finesine[an], (P_Random() & 0x0f) << FRACBITS);
+ mo->momz = (P_Random() & 0x0f) << FRACBITS;
+}
+
+//
+// A_ClaxonBlare
+//
+// [STRIFE] New function
+// haleyjd 09/08/10: The ever-dreadful Strife alarm!
+//
+void A_ClaxonBlare(mobj_t* actor)
+{
+ // Timer ran down?
+ if(--actor->reactiontime < 0)
+ {
+ // reset to initial state
+ actor->target = NULL;
+ actor->reactiontime = actor->info->reactiontime;
+
+ // listen for more noise
+ A_Listen(actor);
+
+ // If we heard something, stay on for a while,
+ // otherwise return to spawnstate.
+ if(actor->target)
+ actor->reactiontime = 50;
+ else
+ P_SetMobjState(actor, actor->info->spawnstate);
+ }
+
+ // When almost ran down, clear the soundtarget so it doesn't
+ // retrigger the alarm.
+ // Also, play the harsh, grating claxon.
+ if(actor->reactiontime == 2)
+ actor->subsector->sector->soundtarget = NULL;
+ else if(actor->reactiontime > 50)
+ S_StartSound(actor, sfx_alarm);
+}
+
+//
+// A_ActiveSound
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Plays an object's active sound periodically.
+//
+void A_ActiveSound(mobj_t* actor)
+{
+ if(actor->info->activesound)
+ {
+ if(!(leveltime & 7)) // haleyjd: added parens
+ S_StartSound(actor, actor->info->activesound);
+ }
+}
+
+//
+// A_ClearSoundTarget
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Clears the actor's sector soundtarget, so that the actor
+// will not be continually alerted/awakened ad infinitum. Used by
+// shopkeepers.
+//
+void A_ClearSoundTarget(mobj_t* actor)
+{
+ actor->subsector->sector->soundtarget = NULL;
+}
+
+//
+// A_DropBurnFlesh
+//
+// villsa [STRIFE] new codepointer
+//
+void A_DropBurnFlesh(mobj_t* actor)
+{
+ mobj_t* mo;
+ mobjtype_t type;
+
+ type = actor->type;
+
+ mo = P_SpawnMobj(actor->x, actor->y, actor->z + (24*FRACUNIT), MT_BURNDROP);
+ mo->momz = -FRACUNIT;
+
+ actor->type = MT_SFIREBALL;
+ P_RadiusAttack(actor, actor, 64);
+ actor->type = type;
+}
+
+//
+// A_FlameDeath
+//
+// villsa [STRIFE] new codepointer
+// 09/06/10: Death animation for flamethrower fireballs.
+//
+void A_FlameDeath(mobj_t* actor)
+{
+ actor->flags |= MF_NOGRAVITY;
+ actor->momz = (P_Random() & 3) << FRACBITS;
+}
+
+//
+// A_ClearForceField
+//
+// villsa [STRIFE] new codepointer
+// check for all matching lines in the sector
+// and disable blocking/midtextures
+//
+void A_ClearForceField(mobj_t* actor)
+{
+ int i;
+ sector_t *sec;
+ line_t *secline;
+
+ actor->flags &= ~(MF_SOLID|MF_SPECIAL);
+ sec = actor->subsector->sector;
+
+ if(!sec->linecount)
+ return;
+
+ for(i = 0; i < sec->linecount; i++)
+ {
+ secline = sec->lines[i];
+ // BUG: will crash if 1S line has TWOSIDED flag!
+ if(!(secline->flags & ML_TWOSIDED))
+ continue;
+ if(secline->special != 148)
+ continue;
+
+ secline->flags &= ~ML_BLOCKING;
+ secline->special = 0;
+ sides[secline->sidenum[0]].midtexture = 0;
+ sides[secline->sidenum[1]].midtexture = 0;
+ }
+}
+
diff --git a/src/strife/p_floor.c b/src/strife/p_floor.c
new file mode 100644
index 00000000..31f2a7cf
--- /dev/null
+++ b/src/strife/p_floor.c
@@ -0,0 +1,590 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// Floor animation: raising stairs.
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "z_zone.h"
+#include "doomdef.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+// Data.
+#include "sounds.h"
+
+
+//
+// FLOORS
+//
+
+//
+// Move a plane (floor or ceiling) and check for crushing
+//
+// [STRIFE] Various changes were made to remove calls to P_ChangeSector when
+// P_ChangeSector returns true.
+//
+result_e
+T_MovePlane
+( sector_t* sector,
+ fixed_t speed,
+ fixed_t dest,
+ boolean crush,
+ int floorOrCeiling,
+ int direction )
+{
+ boolean flag;
+ fixed_t lastpos;
+
+ switch(floorOrCeiling)
+ {
+ case 0:
+ // FLOOR
+ switch(direction)
+ {
+ case -1:
+ // DOWN
+ if (sector->floorheight - speed < dest)
+ {
+ // villsa [STRIFE] unused
+ //lastpos = sector->floorheight;
+ sector->floorheight = dest;
+ flag = P_ChangeSector(sector,crush);
+
+ // villsa [STRIFE] unused
+ /*if (flag == true)
+ {
+ sector->floorheight =lastpos;
+ P_ChangeSector(sector,crush);
+ //return crushed;
+ }*/
+ return pastdest;
+ }
+ else
+ {
+ // villsa [STRIFE] unused
+ //lastpos = sector->floorheight;
+ sector->floorheight -= speed;
+ flag = P_ChangeSector(sector,crush);
+
+ // villsa [STRIFE] unused
+ /*if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector,crush);
+ return crushed;
+ }*/
+ return ok;
+ }
+ break;
+
+ case 1:
+ // UP
+ if (sector->floorheight + speed > dest)
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight = dest;
+ flag = P_ChangeSector(sector,crush);
+ if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector,crush);
+ //return crushed;
+ }
+ return pastdest;
+ }
+ else
+ {
+ // COULD GET CRUSHED
+ lastpos = sector->floorheight;
+ sector->floorheight += speed;
+ flag = P_ChangeSector(sector,crush);
+ if (flag == true)
+ {
+ // haleyjd 20130210: Bug fix - Strife DOES do this.
+ if (crush == true)
+ return crushed;
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector,crush);
+ return crushed;
+ }
+ else
+ return ok;
+ }
+ break;
+ }
+ break;
+
+ case 1:
+ // CEILING
+ switch(direction)
+ {
+ case -1:
+ // DOWN
+ if (sector->ceilingheight - speed < dest)
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight = dest;
+ flag = P_ChangeSector(sector,crush);
+
+ if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector,crush);
+ //return crushed;
+ }
+ return pastdest;
+ }
+ else
+ {
+ // COULD GET CRUSHED
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight -= speed;
+ flag = P_ChangeSector(sector,crush);
+
+ if (flag == true)
+ {
+ if (crush == true)
+ return crushed;
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector,crush);
+ return crushed;
+ }
+ }
+ break;
+
+ case 1:
+ // UP
+ if (sector->ceilingheight + speed > dest)
+ {
+ // villsa [STRIFE] unused
+ //lastpos = sector->ceilingheight;
+ sector->ceilingheight = dest;
+
+ // villsa [STRIFE] unused
+ //flag = P_ChangeSector(sector,crush);
+ /*if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector,crush);
+ //return crushed;
+ }*/
+ return pastdest;
+ }
+ else
+ {
+ // villsa [STRIFE] unused
+ //lastpos = sector->ceilingheight;
+ sector->ceilingheight += speed;
+
+ // villsa [STRIFE] unused
+ //flag = P_ChangeSector(sector,crush);
+ return ok;
+ }
+ break;
+ }
+ break;
+
+ }
+ return ok;
+}
+
+
+//
+// MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
+//
+void T_MoveFloor(floormove_t* floor)
+{
+ result_e res;
+
+ res = T_MovePlane(floor->sector,
+ floor->speed,
+ floor->floordestheight,
+ floor->crush,0,floor->direction);
+
+ if (!(leveltime&7))
+ S_StartSound(&floor->sector->soundorg, sfx_stnmov);
+
+ if (res == pastdest)
+ {
+ floor->sector->specialdata = NULL;
+
+ if (floor->direction == 1)
+ {
+ switch(floor->type)
+ {
+ case donutRaise:
+ floor->sector->special = floor->newspecial;
+ floor->sector->floorpic = floor->texture;
+ default:
+ break;
+ }
+ }
+ else if (floor->direction == -1)
+ {
+ switch(floor->type)
+ {
+ case lowerAndChange:
+ floor->sector->special = floor->newspecial;
+ floor->sector->floorpic = floor->texture;
+ default:
+ break;
+ }
+ }
+ P_RemoveThinker(&floor->thinker);
+
+ S_StartSound(&floor->sector->soundorg, sfx_pstop);
+ }
+
+}
+
+//
+// HANDLE FLOOR TYPES
+//
+// haleyjd 09/16/2010: [STRIFE] Modifications to floortypes:
+// * raiseFloor24 was changed into raiseFloor64
+// * turboLower does not appear to adjust the floor height (STRIFE-TODO: verify)
+// * raiseFloor512AndChange type was added.
+//
+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;
+ while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (sec->specialdata)
+ continue;
+
+ // new floor thinker
+ rtn = 1;
+ floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
+ P_AddThinker (&floor->thinker);
+ sec->specialdata = floor;
+ floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
+ floor->type = floortype;
+ floor->crush = false;
+
+ switch(floortype)
+ {
+ case lowerFloor: // [STRIFE] verified unmodified
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight =
+ P_FindHighestFloorSurrounding(sec);
+ break;
+
+ case lowerFloorToLowest: // [STRIFE] verified unmodified
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight =
+ P_FindLowestFloorSurrounding(sec);
+ break;
+
+ case turboLower: // [STRIFE] Modified: does not += 8
+ 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: // [STRIFE] verified unmodified
+ 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: // [STRIFE] verified unmodified
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED*4;
+ floor->floordestheight =
+ P_FindNextHighestFloor(sec,sec->floorheight);
+ break;
+
+ case raiseFloorToNearest: // [STRIFE] verified unmodified
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight =
+ P_FindNextHighestFloor(sec,sec->floorheight);
+ break;
+
+ case raiseFloor64: // [STRIFE] modified from raiseFloor24!
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight = floor->sector->floorheight +
+ 64 * FRACUNIT; // [STRIFE]
+ break;
+
+ case raiseFloor512: // [STRIFE] verified unmodified
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight = floor->sector->floorheight +
+ 512 * FRACUNIT;
+ break;
+
+ case raiseFloor24AndChange: // [STRIFE] verified unmodified
+ 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;
+ break;
+
+ case raiseFloor512AndChange: // [STRIFE] New floor type
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight = floor->sector->floorheight +
+ 512 * FRACUNIT;
+ sec->floorpic = line->frontsector->floorpic;
+ sec->special = line->frontsector->special;
+ break;
+
+ case raiseToTexture: // [STRIFE] verified unmodified
+ {
+ int minsize = INT_MAX;
+ side_t* side;
+
+ 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);
+ if (side->bottomtexture >= 0)
+ if (textureheight[side->bottomtexture] <
+ minsize)
+ minsize =
+ textureheight[side->bottomtexture];
+ side = getSide(secnum,i,1);
+ if (side->bottomtexture >= 0)
+ if (textureheight[side->bottomtexture] <
+ minsize)
+ minsize =
+ textureheight[side->bottomtexture];
+ }
+ }
+ floor->floordestheight =
+ floor->sector->floorheight + minsize;
+ }
+ break;
+
+ case lowerAndChange: // [STRIFE] verified unmodified
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->speed = FLOORSPEED;
+ floor->floordestheight =
+ P_FindLowestFloorSurrounding(sec);
+ floor->texture = sec->floorpic;
+
+ for (i = 0; i < sec->linecount; i++)
+ {
+ if ( twoSided(secnum, i) )
+ {
+ if (getSide(secnum,i,0)->sector-sectors == secnum)
+ {
+ sec = getSector(secnum,i,1);
+
+ if (sec->floorheight == floor->floordestheight)
+ {
+ floor->texture = sec->floorpic;
+ floor->newspecial = sec->special;
+ break;
+ }
+ }
+ else
+ {
+ sec = getSector(secnum,i,0);
+
+ if (sec->floorheight == floor->floordestheight)
+ {
+ floor->texture = sec->floorpic;
+ floor->newspecial = sec->special;
+ break;
+ }
+ }
+ }
+ }
+ default:
+ break;
+ }
+ }
+ return rtn;
+}
+
+
+
+
+//
+// BUILD A STAIRCASE!
+//
+int
+EV_BuildStairs
+( line_t* line,
+ stair_e type )
+{
+ int secnum;
+ int height;
+ int i;
+ int newsecnum;
+ int texture;
+ int ok;
+ int rtn;
+
+ sector_t* sec;
+ sector_t* tsec;
+
+ floormove_t* floor;
+
+ // Either Watcom or Rogue moved the switch out of the loop below, probably
+ // because it was a loop invariant, and put the default values in the
+ // initializers here. I cannot be bothered to figure it out without doing
+ // this myself :P
+ fixed_t stairsize = 8*FRACUNIT;
+ fixed_t speed = FLOORSPEED;
+ int direction = 1;
+
+ switch(type)
+ {
+ case build8: // [STRIFE] Verified unmodified.
+ speed = FLOORSPEED/4;
+ break;
+ case turbo16: // [STRIFE] Verified unmodified.
+ speed = FLOORSPEED*4;
+ stairsize = 16*FRACUNIT;
+ break;
+ case buildDown16: // [STRIFE] New stair type
+ stairsize = -16*FRACUNIT;
+ direction = -1;
+ break;
+ }
+
+ secnum = -1;
+ rtn = 0;
+ while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (sec->specialdata)
+ continue;
+
+ // new floor thinker
+ rtn = 1;
+ floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
+ P_AddThinker (&floor->thinker);
+ sec->specialdata = floor;
+ floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
+ floor->direction = 1;
+ floor->sector = sec;
+ 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]
+ // 2. Other side is the next sector to raise
+ do
+ {
+ ok = 0;
+ for (i = 0;i < sec->linecount;i++)
+ {
+ if ( !((sec->lines[i])->flags & ML_TWOSIDED) )
+ continue;
+
+ tsec = (sec->lines[i])->frontsector;
+ newsecnum = tsec-sectors;
+
+ if (secnum != newsecnum)
+ continue;
+
+ tsec = (sec->lines[i])->backsector;
+ newsecnum = tsec - sectors;
+
+ if (tsec->floorpic != texture)
+ continue;
+
+ height += stairsize;
+
+ if (tsec->specialdata)
+ continue;
+
+ sec = tsec;
+ secnum = newsecnum;
+ floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
+
+ P_AddThinker (&floor->thinker);
+
+ sec->specialdata = floor;
+ floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
+ floor->direction = direction; // [STRIFE]: for buildDown16
+ floor->sector = sec;
+ floor->speed = speed;
+ floor->floordestheight = height;
+ ok = 1;
+ break;
+ }
+ } while(ok);
+ }
+ return rtn;
+}
+
diff --git a/src/strife/p_inter.c b/src/strife/p_inter.c
new file mode 100644
index 00000000..bd56cbed
--- /dev/null
+++ b/src/strife/p_inter.c
@@ -0,0 +1,1408 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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).
+//
+//-----------------------------------------------------------------------------
+
+// Data.
+#include "doomdef.h"
+#include "dstrings.h"
+#include "sounds.h"
+#include "deh_main.h"
+#include "deh_misc.h"
+#include "doomstat.h"
+#include "m_random.h"
+#include "i_system.h"
+#include "am_map.h"
+#include "p_local.h"
+#include "p_dialog.h" // villsa [STRIFE]
+#include "s_sound.h"
+#include "p_inter.h"
+
+#include "hu_stuff.h" // villsa [STRIFE]
+#include "z_zone.h" // villsa [STRIFE]
+
+// haleyjd [STRIFE]
+#include "w_wad.h"
+#include "p_pspr.h"
+#include "p_dialog.h"
+#include "f_finale.h"
+
+
+#define BONUSADD 6
+
+
+// a weapon is found with two clip loads,
+// a big item has five clip loads
+// villsa [STRIFE] updated arrays
+int maxammo[NUMAMMO] = { 250, 50, 25, 400, 100, 30, 16 };
+int clipammo[NUMAMMO] = { 10, 4, 2, 20, 4, 6, 4 };
+
+
+//
+// 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
+//
+// [STRIFE] Modified for Strife ammo types
+//
+boolean P_GiveAmmo(player_t* player, ammotype_t ammo, int num)
+{
+ int oldammo;
+
+ if(ammo == am_noammo)
+ return false;
+
+ if(ammo > NUMAMMO)
+ I_Error ("P_GiveAmmo: bad type %i", ammo);
+
+ if(player->ammo[ammo] == player->maxammo[ammo])
+ return false;
+
+ if(num)
+ num *= clipammo[ammo];
+ else
+ num = clipammo[ammo]/2;
+
+ if(gameskill == sk_baby
+ || gameskill == sk_nightmare)
+ {
+ // give double ammo in trainer mode,
+ // you'll need in 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.
+
+ // villsa [STRIFE] ammo update
+ // where's the check for grenades? - haleyjd: verified no switch to grenades
+ // haleyjd 10/03/10: don't change to electric bow when picking up poison
+ // arrows.
+ if(!player->readyweapon)
+ {
+ switch(ammo)
+ {
+ case am_bullets:
+ if(player->weaponowned[wp_rifle])
+ player->pendingweapon = wp_rifle;
+ break;
+
+ case am_elecbolts:
+ if(player->weaponowned[wp_elecbow])
+ player->pendingweapon = wp_elecbow;
+ break;
+
+ case am_cell:
+ if(player->weaponowned[wp_mauler])
+ player->pendingweapon = wp_mauler;
+ break;
+
+ case am_missiles:
+ if(player->weaponowned[wp_missile])
+ player->pendingweapon = wp_missile;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+//
+// P_GiveWeapon
+// The weapon name may have a MF_DROPPED flag ored in.
+//
+// villsa [STRIFE] some stuff has been changed/moved around
+//
+boolean P_GiveWeapon(player_t* player, weapontype_t weapon, boolean dropped)
+{
+ boolean gaveammo;
+ boolean gaveweapon;
+
+ // villsa [STRIFE] new code for giving alternate version
+ // of the weapon to player
+ if(player->weaponowned[weapon])
+ gaveweapon = false;
+ else
+ {
+ gaveweapon = true;
+ player->weaponowned[weapon] = true;
+
+ // Alternate "sister" weapons that you also get as a bonus:
+ switch(weapon)
+ {
+ case wp_elecbow:
+ player->weaponowned[wp_poisonbow] = true;
+ break;
+
+ case wp_hegrenade:
+ player->weaponowned[wp_wpgrenade] = true;
+ break;
+
+ case wp_mauler:
+ player->weaponowned[wp_torpedo] = true;
+ break;
+
+ default:
+ break;
+ }
+
+ // check for the standard weapons only
+ if(weapon > player->readyweapon && weapon <= wp_sigil)
+ player->pendingweapon = weapon;
+
+ }
+
+ if(netgame && (deathmatch != 2) && !dropped)
+ {
+ // leave placed weapons forever on net games
+ if(!gaveweapon)
+ return false;
+
+ player->bonuscount += BONUSADD;
+ player->weaponowned[weapon] = true;
+
+ if(deathmatch)
+ P_GiveAmmo(player, weaponinfo[weapon].ammo, 5);
+ else
+ P_GiveAmmo(player, weaponinfo[weapon].ammo, 2);
+
+ if(player == &players[consoleplayer])
+ S_StartSound (NULL, sfx_wpnup);
+ return false;
+ }
+
+ if(weaponinfo[weapon].ammo != am_noammo)
+ {
+ // give one clip with a dropped weapon,
+ // two clips with a found weapon
+ if(dropped)
+ gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
+ else
+ gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
+ }
+ else
+ gaveammo = false;
+
+ return(gaveweapon || gaveammo);
+}
+
+
+
+//
+// P_GiveBody
+// Returns false if the body isn't needed at all
+//
+// villsa [STRIFE] a lot of changes have been added for stamina
+//
+boolean P_GiveBody(player_t* player, int num)
+{
+ int maxhealth;
+ int healing;
+
+ maxhealth = MAXHEALTH + player->stamina;
+
+ if(num >= 0) // haleyjd 20100923: fixed to give proper amount of health
+ {
+ mobj_t *mo; // haleyjd 20110225: needed below...
+
+ // any healing to do?
+ if(player->health >= maxhealth)
+ return false;
+
+ // give, and cap to maxhealth
+ player->health += num;
+ if(player->health >= maxhealth)
+ player->health = maxhealth;
+
+ // Set mo->health for consistency.
+ // haleyjd 20110225: Seems Strife can call this on a NULL player->mo
+ // when giving items to players that are not in the game...
+ mo = P_SubstNullMobj(player->mo);
+ mo->health = player->health;
+ }
+ else
+ {
+ // [STRIFE] handle healing from the Front's medic
+ // The amount the player's health will be set to scales up with stamina
+ // increases.
+ // Ex 1: On the wimpiest skill level, -100 is sent in. This restores
+ // full health no matter what your stamina.
+ // (100*100)/100 = 100
+ // (200*100)/100 = 200
+ // Ex 2: On the most stringent skill levels, -50 is sent in. This will
+ // restore at most half of your health.
+ // (100*50)/100 = 50
+ // (200*50)/100 = 100
+ healing = (-num * maxhealth) / MAXHEALTH;
+
+ // This is also the "threshold" of healing. You need less health than
+ // the amount that will be restored in order to get any benefit.
+ // So on the easiest skill you will always be fully healed.
+ // On the hardest skill you must have less than 50 health, and will
+ // only recover to 50 (assuming base stamina stat)
+ if(player->health >= healing)
+ return false;
+
+ // Set health. BUG: Oddly, mo->health is NOT set here...
+ player->health = healing;
+ }
+
+ return true;
+}
+
+
+
+//
+// P_GiveArmor
+// Returns false if the armor is worse
+// than the current armor.
+//
+// [STRIFE] Modified for Strife armor items
+//
+boolean P_GiveArmor(player_t* player, int armortype)
+{
+ int hits;
+
+ // villsa [STRIFE]
+ if(armortype < 0)
+ {
+ if(player->armorpoints)
+ return false;
+
+ armortype = -armortype;
+ }
+
+ hits = armortype * 100;
+ if(player->armorpoints >= hits)
+ return false; // don't pick up
+
+ player->armortype = armortype;
+ player->armorpoints = hits;
+
+ return true;
+}
+
+
+
+//
+// P_GiveCard
+//
+// [STRIFE] Modified to use larger bonuscount
+//
+boolean P_GiveCard(player_t* player, card_t card)
+{
+ if (player->cards[card])
+ return false;
+
+ // villsa [STRIFE] multiply by 2
+ player->bonuscount = BONUSADD * 2;
+ player->cards[card] = true;
+
+ return true;
+}
+
+
+//
+// P_GivePower
+//
+// [STRIFE] Modifications for new powerups
+//
+boolean P_GivePower(player_t* player, powertype_t power)
+{
+ // haleyjd 09/14/10: [STRIFE] moved to top, exception for Shadow Armor
+ if(player->powers[power] && power != pw_invisibility)
+ return false; // already got it
+
+ // if giving pw_invisibility and player already has MVIS, no can do.
+ if(power == pw_invisibility && (player->mo->flags & MF_MVIS))
+ return false;
+
+ // villsa [STRIFE]
+ if(power == pw_targeter)
+ {
+ player->powers[power] = TARGTICS;
+ P_SetPsprite(player, ps_targcenter, S_TRGT_00); // 10
+ P_SetPsprite(player, ps_targleft, S_TRGT_01); // 11
+ P_SetPsprite(player, ps_targright, S_TRGT_02); // 12
+
+ player->psprites[ps_targcenter].sx = (160*FRACUNIT);
+ player->psprites[ps_targleft ].sy = (100*FRACUNIT);
+ player->psprites[ps_targcenter].sy = (100*FRACUNIT);
+ player->psprites[ps_targright ].sy = (100*FRACUNIT);
+ return true;
+ }
+
+ if(power == pw_invisibility)
+ {
+ // if player already had this power...
+ if(player->powers[power])
+ {
+ // remove SHADOW, give MVIS.
+ player->mo->flags &= ~MF_SHADOW;
+ player->mo->flags |= MF_MVIS;
+ }
+ else // give SHADOW
+ player->mo->flags |= MF_SHADOW;
+
+ // set tics if giving shadow, or renew them if MVIS.
+ player->powers[power] = INVISTICS;
+
+ return true;
+ }
+
+ if(power == pw_ironfeet)
+ {
+ player->powers[power] = IRONTICS;
+ return true;
+ }
+
+ if(power == pw_strength)
+ {
+ P_GiveBody(player, 100);
+ player->powers[power] = 1;
+ return true;
+ }
+
+ // villsa [STRIFE]
+ if(power == pw_allmap)
+ {
+ // remember in mapstate
+ if(gamemap < 40)
+ player->mapstate[gamemap] = true;
+
+ player->powers[power] = 1;
+ return true;
+ }
+
+ // villsa [STRIFE]
+ if(power == pw_communicator)
+ {
+ player->powers[power] = 1;
+ return true;
+ }
+
+ // default behavior:
+ player->powers[power] = 1;
+ return true;
+}
+
+
+// villsa [STRIFE]
+static char pickupmsg[80];
+
+//
+// P_TouchSpecialThing
+//
+// [STRIFE] Rewritten for Strife collectables.
+//
+void P_TouchSpecialThing(mobj_t* special, mobj_t* toucher)
+{
+ player_t* player;
+ int i;
+ fixed_t delta;
+ int sound;
+
+ 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;
+
+ // villsa [STRIFE] damage toucher if special is spectral
+ // haleyjd 09/21/10: corrected to test for SPECTRE thingtypes specifically
+ switch(special->type)
+ {
+ case MT_SPECTRE_A:
+ case MT_SPECTRE_B:
+ case MT_SPECTRE_C:
+ case MT_SPECTRE_D:
+ case MT_SPECTRE_E:
+ case MT_ENTITY:
+ case MT_SUBENTITY:
+ P_DamageMobj(toucher, NULL, NULL, 5);
+ return;
+ default:
+ break;
+ }
+
+ // villsa [STRIFE]
+ pickupmsg[0] = 0;
+
+ // Identify by sprite.
+ // villsa [STRIFE] new items
+ switch(special->sprite)
+ {
+ // bullets
+ case SPR_BLIT: // haleyjd: fixed missing MF_DROPPED check
+ if(!P_GiveAmmo(player, am_bullets, !(special->flags & MF_DROPPED)))
+ return;
+ break;
+
+ // box of bullets
+ case SPR_BBOX:
+ if(!P_GiveAmmo(player, am_bullets, 5))
+ return;
+ break;
+
+ // missile
+ case SPR_ROKT:
+ if(!P_GiveAmmo(player, am_missiles, 1))
+ return;
+ break;
+
+ // box of missiles
+ case SPR_MSSL:
+ if(!P_GiveAmmo(player, am_missiles, 5))
+ return;
+ break;
+
+ // battery
+ case SPR_BRY1:
+ if(!P_GiveAmmo(player, am_cell, 1))
+ return;
+ break;
+
+ // cell pack
+ case SPR_CPAC:
+ if(!P_GiveAmmo(player, am_cell, 5))
+ return;
+ break;
+
+ // poison bolts
+ case SPR_PQRL:
+ if(!P_GiveAmmo(player, am_poisonbolts, 5))
+ return;
+ break;
+
+ // electric bolts
+ case SPR_XQRL:
+ if(!P_GiveAmmo(player, am_elecbolts, 5))
+ return;
+ break;
+
+ // he grenades
+ case SPR_GRN1:
+ if(!P_GiveAmmo(player, am_hegrenades, 1))
+ return;
+ break;
+
+ // wp grenades
+ case SPR_GRN2:
+ if(!P_GiveAmmo(player, am_wpgrenades, 1))
+ return;
+ break;
+
+ // rifle
+ case SPR_RIFL:
+ if(!P_GiveWeapon(player, wp_rifle, special->flags & MF_DROPPED))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // flame thrower
+ case SPR_FLAM:
+ if(!P_GiveWeapon(player, wp_flame, false))
+ return;
+ // haleyjd: gives extra ammo.
+ P_GiveAmmo(player, am_cell, 3);
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // missile launcher
+ case SPR_MMSL:
+ if(!P_GiveWeapon(player, wp_missile, false))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // grenade launcher
+ case SPR_GRND:
+ if(!P_GiveWeapon(player, wp_hegrenade, special->flags & MF_DROPPED))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // mauler
+ case SPR_TRPD:
+ if(!P_GiveWeapon(player, wp_mauler, false))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // electric bolt crossbow
+ case SPR_CBOW:
+ if(!P_GiveWeapon(player, wp_elecbow, special->flags & MF_DROPPED))
+ return;
+ sound = sfx_wpnup; // haleyjd: SHK-CHK!
+ break;
+
+ // haleyjd 09/21/10: missed case: THE SIGIL!
+ case SPR_SIGL:
+ if(!P_GiveWeapon(player, wp_sigil, special->flags & MF_DROPPED))
+ {
+ player->sigiltype = special->frame;
+ return;
+ }
+
+ if(netgame)
+ player->sigiltype = 4;
+
+ player->pendingweapon = wp_sigil;
+ player->st_update = true;
+ if(deathmatch)
+ return;
+ sound = sfx_wpnup;
+ break;
+
+ // backpack
+ case SPR_BKPK:
+ 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);
+ break;
+
+ // 1 Gold
+ case SPR_COIN:
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ // 10 Gold
+ case SPR_CRED:
+ for(i = 0; i < 10; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ // 25 Gold
+ case SPR_SACK:
+ // haleyjd 09/21/10: missed code: if a SPR_SACK object has negative
+ // health, it will give that much gold - STRIFE-TODO: verify
+ if(special->health < 0)
+ {
+ for(i = special->health; i != 0; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ }
+ else
+ {
+ for(i = 0; i < 25; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ }
+ break;
+
+ // 50 Gold
+ case SPR_CHST:
+ for(i = 0; i < 50; i++)
+ P_GiveInventoryItem(player, SPR_COIN, MT_MONY_1);
+ break;
+
+ // Leather Armor
+ case SPR_ARM1:
+ if(!P_GiveArmor(player, -2))
+ if(!P_GiveInventoryItem(player, special->sprite, special->type))
+ pickupmsg[0] = '!';
+ break;
+
+ // Metal Armor
+ case SPR_ARM2:
+ if(!P_GiveArmor(player, -1))
+ if(!P_GiveInventoryItem(player, special->sprite, special->type))
+ pickupmsg[0] = '!';
+ break;
+
+ // All-map powerup
+ case SPR_PMAP:
+ if(!P_GivePower(player, pw_allmap))
+ return;
+ sound = sfx_yeah;
+ break;
+
+ // The Comm Unit - because you need Blackbird whining in your ear the
+ // whole time and telling you how lost she is :P
+ case SPR_COMM:
+ if(!P_GivePower(player, pw_communicator))
+ return;
+ sound = sfx_yeah;
+ break;
+
+ // haleyjd 09/21/10: missed case - Shadow Armor; though, I do not know why
+ // this has a case distinct from generic inventory items... Maybe it started
+ // out as an auto-use-if-possible item much like regular armor...
+ case SPR_SHD1:
+ if(!P_GiveInventoryItem(player, SPR_SHD1, special->type))
+ pickupmsg[0] = '!';
+ break;
+
+ // villsa [STRIFE] check default items
+ case SPR_TOKN:
+ default:
+ if(special->type >= MT_KEY_BASE && special->type <= MT_NEWKEY5)
+ {
+ // haleyjd 09/21/10: Strife player still picks up keys that
+ // he has already found. (break, not return)
+ if(!P_GiveCard(player, special->type - MT_KEY_BASE))
+ break;
+ }
+ else
+ {
+ if(!P_GiveInventoryItem(player, special->sprite, special->type))
+ pickupmsg[0] = '!';
+ }
+ break;
+ }
+
+ // villsa [STRIFE] set message
+ if(!pickupmsg[0])
+ {
+ if(special->info->name)
+ {
+ DEH_snprintf(pickupmsg, sizeof(pickupmsg),
+ "You picked up the %s.", DEH_String(special->info->name));
+ }
+ else
+ DEH_snprintf(pickupmsg, sizeof(pickupmsg), "You picked up the item.");
+ }
+ // use the first character to indicate that the player is full on items
+ else if(pickupmsg[0] == '!')
+ {
+ DEH_snprintf(pickupmsg, sizeof(pickupmsg), "You cannot hold any more.");
+ player->message = pickupmsg;
+ return;
+ }
+
+ if(special->flags & MF_GIVEQUEST)
+ {
+ // [STRIFE]: Award quest flag based on the thing's speed. Quest 8 was
+ // apparently at some point given by the Broken Power Coupling, which is
+ // why they don't want to award it if you have Quest 6 (which is
+ // acquired by destroying the Front's working power coupling). BUT, the
+ // broken coupling object's speed is NOT 8... it is 512*FRACUNIT. For
+ // strict portability beyond the x86, we need to AND the operand by 31.
+ if(special->info->speed != 8 || !(player->questflags & QF_QUEST6))
+ player->questflags |= 1 << ((special->info->speed - 1) & 31);
+ }
+
+
+ // haleyjd 08/30/10: [STRIFE] No itemcount
+ //if (special->flags & MF_COUNTITEM)
+ // player->itemcount++;
+
+ P_RemoveMobj(special);
+ player->message = pickupmsg;
+ player->bonuscount += BONUSADD;
+
+ if(player == &players[consoleplayer])
+ S_StartSound(NULL, sound);
+}
+
+// villsa [STRIFE]
+static char plrkilledmsg[80];
+
+//
+// KillMobj
+//
+// [STRIFE] Major modifications for drop types, no tic randomization, etc.
+//
+void P_KillMobj(mobj_t* source, mobj_t* target)
+{
+ mobjtype_t item;
+ mobj_t* mo;
+ line_t junk;
+ int i;
+
+ // villsa [STRIFE] corpse and dropoff are removed, but why when these two flags
+ // are set a few lines later? watcom nonsense perhaps?
+ target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_BOUNCE|MF_CORPSE|MF_DROPOFF);
+
+ // villsa [STRIFE] unused
+ /*
+ if (target->type != MT_SKULL)
+ target->flags &= ~MF_NOGRAVITY;
+ */
+
+ target->flags |= MF_CORPSE|MF_DROPOFF;
+ target->height = FRACUNIT; // villsa [STRIFE] set to fracunit instead of >>= 2
+
+ if(source && source->player)
+ {
+ // count for intermission
+ if(target->flags & MF_COUNTKILL)
+ source->player->killcount++;
+
+ if(target->player)
+ {
+ source->player->frags[target->player-players]++;
+
+ // villsa [STRIFE] new messages when fragging players
+ DEH_snprintf(plrkilledmsg, sizeof(plrkilledmsg),
+ "%s killed %s",
+ pnameprefixes[source->player->mo->miscdata],
+ pnameprefixes[target->player->mo->miscdata]);
+
+ if(netgame)
+ players[consoleplayer].message = plrkilledmsg;
+ }
+ }
+ else if(!netgame && (target->flags & MF_COUNTKILL))
+ {
+ // count all monster deaths,
+ // even those caused by other monsters
+ players[0].killcount++;
+ }
+
+ if(target->player)
+ {
+ // count environment kills against you
+ if(!source)
+ target->player->frags[target->player-players]++;
+
+ if(gamemap == 29 && !netgame)
+ {
+ // haleyjd 09/13/10: [STRIFE] Give player the bad ending.
+ F_StartFinale();
+ return;
+ }
+
+ // villsa [STRIFE] spit out inventory items when killed
+ if(netgame)
+ {
+ int amount = 0;
+ mobj_t* loot;
+ int r = 0;
+
+ while(1)
+ {
+ if(target->player->inventory[0].amount <= 0)
+ break;
+
+ item = target->player->inventory[0].type;
+ if(item == MT_MONY_1)
+ {
+ loot = P_SpawnMobj(target->x, target->y,
+ target->z + (24*FRACUNIT), MT_MONY_25);
+
+ // [STRIFE] TODO - what the hell is it doing here?
+ loot->health = target->player->inventory[0].amount;
+ loot->health = -target->player->inventory[0].amount;
+
+ amount = target->player->inventory[0].amount;
+ }
+ else
+ {
+ loot = P_SpawnMobj(target->x, target->y,
+ target->z + (24*FRACUNIT), item);
+ amount = 1;
+ }
+
+ P_RemoveInventoryItem(target->player, 0, amount);
+ r = P_Random();
+ loot->momx += ((r & 7) - (P_Random() & 7)) << FRACBITS;
+ loot->momy += ((P_Random() & 7) + 1) << FRACBITS;
+ loot->flags |= MF_DROPPED;
+ }
+ }
+
+ target->flags &= ~MF_SOLID;
+ target->player->playerstate = PST_DEAD;
+ target->player->mo->momz = 5*FRACUNIT; // [STRIFE]: small hop!
+ P_DropWeapon(target->player);
+
+ if(target->player == &players[consoleplayer]
+ && automapactive)
+ {
+ // don't die in auto map,
+ // switch view prior to dying
+ AM_Stop ();
+ }
+
+ }
+
+ // villsa [STRIFE] some modifications to setting states
+ if(target->state != &states[S_BURN_23])
+ {
+ if(target->health == -6666)
+ P_SetMobjState(target, S_DISR_00); // 373
+ else
+ {
+ if(target->health < -target->info->spawnhealth
+ && target->info->xdeathstate)
+ P_SetMobjState(target, target->info->xdeathstate);
+ else
+ P_SetMobjState(target, target->info->deathstate);
+ }
+ }
+
+ // villsa [STRIFE] no death tics randomization
+
+ // Drop stuff.
+ // villsa [STRIFE] get item from dialog target
+ item = P_DialogFind(target->type, target->miscdata)->dropitem;
+
+ if(!item)
+ {
+ // villsa [STRIFE] drop default items
+ switch(target->type)
+ {
+ case MT_ORACLE:
+ item = MT_MEAT;
+ break;
+
+ case MT_PROGRAMMER:
+ item = MT_SIGIL_A;
+ break;
+
+ case MT_PRIEST:
+ item = MT_JUNK;
+ break;
+
+ case MT_BISHOP:
+ item = MT_AMINIBOX;
+ break;
+
+ case MT_PGUARD:
+ case MT_CRUSADER:
+ item = MT_ACELL;
+ break;
+
+ case MT_RLEADER:
+ item = MT_AAMMOBOX;
+ break;
+
+ case MT_GUARD1:
+ case MT_REBEL1:
+ case MT_SHADOWGUARD:
+ item = MT_ACLIP;
+ break;
+
+ case MT_SPECTRE_B:
+ item = MT_SIGIL_B;
+ break;
+
+ case MT_SPECTRE_C:
+ item = MT_SIGIL_C;
+ break;
+
+ case MT_SPECTRE_D:
+ item = MT_SIGIL_D;
+ break;
+
+ case MT_SPECTRE_E:
+ item = MT_SIGIL_E;
+ break;
+
+ case MT_COUPLING:
+ junk.tag = 225;
+ EV_DoDoor(&junk, close);
+
+ junk.tag = 44;
+ EV_DoFloor(&junk, lowerFloor);
+
+ GiveVoiceObjective("VOC13", "LOG13", 0);
+
+ item = MT_COUPLING_BROKEN;
+ players[0].questflags |= (1 << (mobjinfo[MT_COUPLING].speed - 1));
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ // handle special case for scripted target's dropped item
+ switch(item)
+ {
+ case MT_TOKEN_SHOPCLOSE:
+ junk.tag = 222;
+ EV_DoDoor(&junk, close);
+ P_NoiseAlert(players[0].mo, players[0].mo);
+
+ sprintf(plrkilledmsg, "%s", DEH_String("You're dead! You set off the alarm."));
+ if(!deathmatch)
+ players[consoleplayer].message = plrkilledmsg;
+
+ return;
+
+ case MT_TOKEN_PRISON_PASS:
+ junk.tag = 223;
+ EV_DoDoor(&junk, open);
+ return;
+
+ case MT_TOKEN_DOOR3:
+ junk.tag = 224;
+ EV_DoDoor(&junk, open);
+ return;
+
+ case MT_SIGIL_A:
+ case MT_SIGIL_B:
+ case MT_SIGIL_C:
+ case MT_SIGIL_D:
+ case MT_SIGIL_E:
+ for(i = 0; i < MAXPLAYERS; i++)
+ {
+ if(!P_GiveWeapon(&players[i], wp_sigil, false))
+ {
+ if(players[i].sigiltype++ > 4)
+ players[i].sigiltype = 4;
+ }
+
+ // haleyjd 20110225: fixed these two assignments which Watcom munged
+ // up in the assembly by pre-incrementing the pointer into players[]
+ players[i].st_update = true;
+ players[i].pendingweapon = wp_sigil;
+ }
+ return;
+
+ case MT_TOKEN_ALARM:
+ P_NoiseAlert(players[0].mo, players[0].mo);
+
+ sprintf(plrkilledmsg, "%s", DEH_String("You Fool! You've set off the alarm"));
+ if(!deathmatch)
+ players[consoleplayer].message = plrkilledmsg;
+ return;
+
+ default:
+ break;
+ }
+
+ // villsa [STRIFE] toss out item
+ if(!deathmatch || !(mobjinfo[item].flags & MF_NOTDMATCH))
+ {
+ int r;
+
+ mo = P_SpawnMobj(target->x, target->y, target->z + (24*FRACUNIT), item);
+ r = P_Random();
+ mo->momx += ((r & 7) - (P_Random() & 7)) << FRACBITS;
+ r = P_Random();
+ mo->momy += ((r & 7) - (P_Random() & 7)) << FRACBITS;
+ mo->flags |= (MF_SPECIAL|MF_DROPPED); // special versions of items
+ }
+}
+
+//
+// P_IsMobjBoss
+//
+// villsa [STRIFE] new function
+//
+static boolean P_IsMobjBoss(mobjtype_t type)
+{
+ switch(type)
+ {
+ case MT_PROGRAMMER:
+ case MT_BISHOP:
+ case MT_RLEADER:
+ case MT_ORACLE:
+ case MT_PRIEST:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+
+//
+// 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.
+//
+// [STRIFE] Extensive changes for spectrals, fire damage, disintegration, and
+// a plethora of mobjtype-specific hacks.
+//
+void P_DamageMobj(mobj_t* target, mobj_t* inflictor, mobj_t* source, int damage)
+{
+ angle_t ang;
+ int saved;
+ player_t* player;
+ fixed_t thrust;
+ int temp;
+
+ if(!(target->flags & MF_SHOOTABLE) )
+ return; // shouldn't happen...
+
+ if(target->health <= 0)
+ return;
+
+ player = target->player;
+
+ // villsa [STRIFE] unused - skullfly check (removed)
+
+ // villsa [STRIFE] handle spectral stuff
+ // notes on projectile health:
+ // -2 == enemy spectral projectile
+ // -1 == player spectral projectile
+
+ // haleyjd 20110203: refactored completely
+ if(inflictor && (inflictor->flags & MF_SPECTRAL))
+ {
+ // players aren't damaged by their own (or others???) sigils
+ // STRIFE-TODO: verify in deathmatch
+ if(target->type == MT_PLAYER && inflictor->health == -1)
+ return;
+ // enemies aren't damaged by enemy sigil attacks
+ if((target->flags & MF_SPECTRAL) && inflictor->health == -2)
+ return;
+ // Macil2, Oracle, and Spectre C cannot be damaged by Sigil A
+ switch(target->type)
+ {
+ case MT_RLEADER2:
+ case MT_ORACLE:
+ case MT_SPECTRE_C:
+ // haleyjd: added source->player validity check for safety...
+ if(source->player && source->player->sigiltype < 1)
+ return;
+ default:
+ break;
+ }
+ }
+
+ // villsa [STRIFE] new checks for various actors
+ if(inflictor)
+ {
+ // Fire damage inflictors
+ if(inflictor->type == MT_SFIREBALL ||
+ inflictor->type == MT_C_FLAME ||
+ inflictor->type == MT_PFLAME)
+ {
+ temp = damage / 2;
+
+ if(P_IsMobjBoss(target->type))
+ damage /= 2;
+ else if(inflictor->type == MT_PFLAME)
+ {
+ damage /= 2;
+ // robots take very little damage
+ if(target->flags & MF_NOBLOOD)
+ damage = temp / 2;
+ }
+ }
+ else
+ {
+ switch(inflictor->type)
+ {
+ case MT_HOOKSHOT:
+ // haleyjd 20110203: should use source, not inflictor
+ ang = R_PointToAngle2(
+ target->x,
+ target->y,
+ source->x,
+ source->y) >> ANGLETOFINESHIFT;
+
+ target->momx += FixedMul(finecosine[ang], (12750*FRACUNIT) / target->info->mass);
+ target->momy += FixedMul(finesine[ang], (12750*FRACUNIT) / target->info->mass);
+ target->reactiontime += 10;
+
+ temp = P_AproxDistance(target->x - source->x, target->y - source->y);
+ temp /= target->info->mass;
+
+ if(temp < 1)
+ temp = 1;
+
+ target->momz = (source->z - target->z) / temp;
+ break;
+
+ case MT_POISARROW:
+ // don't affect robots
+ if(target->flags & MF_NOBLOOD)
+ return;
+
+ // instant kill
+ damage = target->health + 10;
+ break;
+
+ default:
+ // Spectral retaliation, though this may in fact be unreachable
+ // since non-spectral inflictors are mostly filtered out.
+ if(target->flags & MF_SPECTRAL
+ && !(inflictor->flags & MF_SPECTRAL))
+ {
+ P_SetMobjState(target, target->info->missilestate);
+ return; // take no damage
+ }
+ break;
+ }
+ }
+ }
+
+ // villsa [STRIFE] special cases for shopkeepers and macil
+ if((target->type >= MT_SHOPKEEPER_W && target->type <= MT_SHOPKEEPER_M)
+ || target->type == MT_RLEADER)
+ {
+ if(source)
+ target->target = source;
+
+ P_SetMobjState(target, target->info->painstate);
+ return;
+ }
+
+ // villsa [STRIFE] handle fieldguard damage
+ if(target->type == MT_FIELDGUARD)
+ {
+ // degnin ores are only allowed to damage the fieldguard
+ if(!inflictor || inflictor->type != MT_DEGNINORE)
+ return;
+
+ damage = target->health;
+ }
+
+ 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_flame))
+ {
+ ang = R_PointToAngle2(inflictor->x,
+ inflictor->y,
+ target->x,
+ target->y);
+
+ 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() & 1))
+ {
+ ang += ANG180;
+ thrust *= 4;
+ }
+
+ ang >>= ANGLETOFINESHIFT;
+ target->momx += FixedMul (thrust, finecosine[ang]);
+ target->momy += FixedMul (thrust, finesine[ang]);
+ }
+
+ // 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.
+ // villsa [STRIFE] removed pw_invulnerability check
+ if(damage < 1000 && (player->cheats & CF_GODMODE))
+ return;
+
+ // villsa [STRIFE] flame attacks don't damage player if wearing envirosuit
+ if(player->powers[pw_ironfeet] && inflictor)
+ {
+ if(inflictor->type == MT_SFIREBALL ||
+ inflictor->type == MT_C_FLAME ||
+ inflictor->type == MT_PFLAME)
+ {
+ damage = 0;
+ }
+ }
+
+ if(player->armortype)
+ {
+ if (player->armortype == 1)
+ saved = damage/3;
+ else
+ saved = damage/2;
+
+ if(player->armorpoints <= saved)
+ {
+ // armor is used up
+ saved = player->armorpoints;
+ player->armortype = 0;
+
+ // villsa [STRIFE]
+ P_UseInventoryItem(player, SPR_ARM1);
+ P_UseInventoryItem(player, SPR_ARM2);
+ }
+ player->armorpoints -= saved;
+ damage -= saved;
+ }
+ player->health -= damage; // mirror mobj health here for Dave
+
+ // [STRIFE] haleyjd 20130302: bug fix - this is *not* capped here.
+ //if(player->health < 0)
+ // player->health = 0;
+
+ player->attacker = source;
+ player->damagecount += damage; // add damage after armor / invuln
+
+ // haleyjd 20110203 [STRIFE]: target->target set here
+ if(target != source)
+ target->target = source;
+
+ if(player->damagecount > 100)
+ player->damagecount = 100; // teleport stomp does 10k points...
+
+ temp = damage < 100 ? damage : 100;
+
+ if(player == &players[consoleplayer])
+ I_Tactile (40,10,40+temp*2);
+ }
+
+ // do the damage
+ target->health -= damage;
+
+ // villsa [STRIFE] auto use medkits
+ if(player && player->health < 50)
+ {
+ if(deathmatch || player->cheats & CF_AUTOHEALTH)
+ {
+ while(player->health < 50 && P_UseInventoryItem(player, SPR_MDKT));
+ while(player->health < 50 && P_UseInventoryItem(player, SPR_STMP));
+ }
+ }
+
+
+ if(target->health <= 0)
+ {
+ // villsa [STRIFE] grenades hurt... OUCH
+ if(inflictor && inflictor->type == MT_HEGRENADE)
+ target->health = -target->info->spawnhealth;
+ else if(!(target->flags & MF_NOBLOOD))
+ {
+ // villsa [STRIFE] disintegration death
+ if(inflictor &&
+ (inflictor->type == MT_STRIFEPUFF3 ||
+ inflictor->type == MT_L_LASER ||
+ inflictor->type == MT_TORPEDO ||
+ inflictor->type == MT_TORPEDOSPREAD))
+ {
+ S_StartSound(target, sfx_dsrptr);
+ target->health = -6666;
+ }
+ }
+
+ // villsa [STRIFE] flame death stuff
+ if(!(target->flags & MF_NOBLOOD)
+ && inflictor
+ && (inflictor->type == MT_SFIREBALL ||
+ inflictor->type == MT_C_FLAME ||
+ inflictor->type == MT_PFLAME))
+ {
+ target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SHADOW|MF_MVIS);
+ if(target->player)
+ {
+ target->player->cheats |= CF_ONFIRE;
+ target->player->powers[pw_communicator] = false;
+ target->player->readyweapon = 0;
+ P_SetPsprite(target->player, ps_weapon, S_WAVE_00); // 02
+ P_SetPsprite(target->player, ps_flash, S_NULL);
+ }
+
+ P_SetMobjState(target, S_BURN_00); // 349
+ S_StartSound(target, sfx_burnme);
+
+ return;
+ }
+
+ P_KillMobj(source, target);
+ return;
+ }
+
+ // villsa [STRIFE] set crash state
+ if(target->health <= 6 && target->info->crashstate)
+ {
+ P_SetMobjState(target, target->info->crashstate);
+ return;
+ }
+
+ if(damage)
+ {
+ // villsa [STRIFE] removed unused skullfly flag
+ if(P_Random() < target->info->painchance)
+ {
+ target->flags |= MF_JUSTHIT; // fight back!
+ P_SetMobjState (target, target->info->painstate);
+ }
+ }
+
+ target->reactiontime = 0; // we're awake now...
+
+ // villsa [STRIFE] new checks for thing types
+ if (target->type != MT_PROGRAMMER
+ && (!target->threshold || target->type == MT_ENTITY)
+ && source && source != target
+ && source->type != MT_ENTITY
+ && ((source->flags & MF_ALLY) != (target->flags & MF_ALLY)))
+ {
+ // if not intent on another player,
+ // chase after this one
+ target->target = source;
+ target->threshold = BASETHRESHOLD;
+
+ if(target->state == &states[target->info->spawnstate]
+ && target->info->seestate != S_NULL)
+ P_SetMobjState (target, target->info->seestate);
+ }
+}
+
diff --git a/src/strife/p_inter.h b/src/strife/p_inter.h
new file mode 100644
index 00000000..1ddf4498
--- /dev/null
+++ b/src/strife/p_inter.h
@@ -0,0 +1,40 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+//
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __P_INTER__
+#define __P_INTER__
+
+// haleyjd [STRIFE]: Multiple externals added
+boolean P_GiveCard(player_t* player, card_t card);
+boolean P_GiveBody(player_t* player, int num);
+boolean P_GiveArmor(player_t* player, int armortype);
+boolean P_GivePower(player_t* player, powertype_t power);
+boolean P_GiveAmmo(player_t* player, ammotype_t ammo, int num);
+boolean P_GiveWeapon(player_t* player, weapontype_t weapon, boolean dropped);
+void P_KillMobj(mobj_t* source, mobj_t* target);
+
+#endif
diff --git a/src/strife/p_lights.c b/src/strife/p_lights.c
new file mode 100644
index 00000000..1b5e1d8c
--- /dev/null
+++ b/src/strife/p_lights.c
@@ -0,0 +1,380 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// Handle Sector base lighting effects.
+// Muzzle flash?
+//
+//-----------------------------------------------------------------------------
+
+
+
+#include "z_zone.h"
+#include "m_random.h"
+
+#include "doomdef.h"
+#include "p_local.h"
+
+
+// State.
+#include "r_state.h"
+
+//
+// FIRELIGHT FLICKER
+//
+
+//
+// T_FireFlicker
+//
+// [STRIFE]
+// haleyjd 2011023: Changes to amount and duration of flicker
+//
+void T_FireFlicker (fireflicker_t* flick)
+{
+ int amount;
+
+ if (--flick->count)
+ return;
+
+ amount = (P_Random() & 3) * 8; // [STRIFE] 16 -> 8
+
+ if (flick->sector->lightlevel - amount < flick->minlight)
+ flick->sector->lightlevel = flick->minlight;
+ else
+ flick->sector->lightlevel = flick->maxlight - amount;
+
+ // [STRIFE] flicker count made random!
+ flick->count = (P_Random() & 3) + 1;
+}
+
+
+
+//
+// P_SpawnFireFlicker
+//
+// [STRIFE]
+// haleyjd 2011023: Changes to minimum light level and initial duration
+//
+void P_SpawnFireFlicker (sector_t* sector)
+{
+ fireflicker_t* flick;
+
+ // Note that we are resetting sector attributes.
+ // Nothing special about it during gameplay.
+ sector->special = 0;
+
+ flick = Z_Malloc ( sizeof(*flick), PU_LEVSPEC, 0);
+
+ P_AddThinker (&flick->thinker);
+
+ flick->thinker.function.acp1 = (actionf_p1) T_FireFlicker;
+ flick->sector = sector;
+ flick->maxlight = sector->lightlevel;
+ flick->minlight = sector->lightlevel - 32; // [STRIFE] changed from min surrounding+16
+ flick->count = 2; // [STRIFE]: Initial count 4 -> 2
+}
+
+
+
+//
+// BROKEN LIGHT FLASHING
+//
+
+
+//
+// T_LightFlash
+// Do flashing lights.
+//
+// [STRIFE] Verified unmodified
+//
+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()&flash->mintime)+1;
+ }
+ else
+ {
+ flash->sector->lightlevel = flash->maxlight;
+ flash->count = (P_Random()&flash->maxtime)+1;
+ }
+}
+
+
+
+
+//
+// P_SpawnLightFlash
+// After the map has been loaded, scan each sector
+// for specials that spawn thinkers
+//
+// [STRIFE] Verified unmodified
+//
+void P_SpawnLightFlash (sector_t* sector)
+{
+ lightflash_t* flash;
+
+ // nothing special about it during gameplay
+ sector->special = 0;
+
+ flash = Z_Malloc ( sizeof(*flash), PU_LEVSPEC, 0);
+
+ P_AddThinker (&flash->thinker);
+
+ flash->thinker.function.acp1 = (actionf_p1) 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()&flash->maxtime)+1;
+}
+
+
+
+//
+// STROBE LIGHT FLASHING
+//
+
+
+//
+// T_StrobeFlash
+//
+// [STRIFE] Verified unmodified
+//
+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;
+ }
+}
+
+
+
+//
+// P_SpawnStrobeFlash
+// After the map has been loaded, scan each sector
+// for specials that spawn thinkers
+//
+// [STRIFE] Verified unmodified
+//
+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.acp1 = (actionf_p1) 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 = 0;
+
+ if (!inSync)
+ flash->count = (P_Random()&7)+1;
+ else
+ flash->count = 1;
+}
+
+
+//
+// Start strobing lights (usually from a trigger)
+//
+// [STRIFE] Verified unmodified
+//
+void EV_StartLightStrobing(line_t* line)
+{
+ int secnum;
+ sector_t* sec;
+
+ secnum = -1;
+ while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if (sec->specialdata)
+ continue;
+
+ P_SpawnStrobeFlash (sec, SLOWDARK, 0);
+ }
+}
+
+
+
+//
+// TURN LINE'S TAG LIGHTS OFF
+//
+// [STRIFE] Verified unmodified
+//
+void EV_TurnTagLightsOff(line_t* line)
+{
+ int i;
+ int j;
+ int min;
+ sector_t* sector;
+ sector_t* tsec;
+ line_t* templine;
+
+ sector = sectors;
+
+ for (j = 0;j < numsectors; j++, sector++)
+ {
+ if (sector->tag == line->tag)
+ {
+ min = sector->lightlevel;
+ for (i = 0;i < sector->linecount; i++)
+ {
+ templine = sector->lines[i];
+ tsec = getNextSector(templine,sector);
+ if (!tsec)
+ continue;
+ if (tsec->lightlevel < min)
+ min = tsec->lightlevel;
+ }
+ sector->lightlevel = min;
+ }
+ }
+}
+
+
+//
+// TURN LINE'S TAG LIGHTS ON
+//
+// [STRIFE] Verified unmodified
+//
+void
+EV_LightTurnOn
+( line_t* line,
+ int bright )
+{
+ int i;
+ int j;
+ sector_t* sector;
+ sector_t* temp;
+ line_t* templine;
+
+ sector = sectors;
+
+ for (i=0;i<numsectors;i++, sector++)
+ {
+ if (sector->tag == line->tag)
+ {
+ // bright = 0 means to search
+ // for highest light level
+ // surrounding sector
+ if (!bright)
+ {
+ for (j = 0;j < sector->linecount; j++)
+ {
+ templine = sector->lines[j];
+ temp = getNextSector(templine,sector);
+
+ if (!temp)
+ continue;
+
+ if (temp->lightlevel > bright)
+ bright = temp->lightlevel;
+ }
+ }
+ sector-> lightlevel = bright;
+ }
+ }
+}
+
+
+//
+// Spawn glowing light
+//
+// [STRIFE] Verified unmodified
+//
+void T_Glow(glow_t* g)
+{
+ switch(g->direction)
+ {
+ case -1:
+ // DOWN
+ g->sector->lightlevel -= GLOWSPEED;
+ if (g->sector->lightlevel <= g->minlight)
+ {
+ g->sector->lightlevel += GLOWSPEED;
+ g->direction = 1;
+ }
+ break;
+
+ case 1:
+ // UP
+ g->sector->lightlevel += GLOWSPEED;
+ if (g->sector->lightlevel >= g->maxlight)
+ {
+ g->sector->lightlevel -= GLOWSPEED;
+ g->direction = -1;
+ }
+ break;
+ }
+}
+
+//
+// [STRIFE] Verified unmodified
+//
+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.acp1 = (actionf_p1) T_Glow;
+ g->direction = -1;
+
+ sector->special = 0;
+}
+
diff --git a/src/strife/p_local.h b/src/strife/p_local.h
new file mode 100644
index 00000000..096b8b6c
--- /dev/null
+++ b/src/strife/p_local.h
@@ -0,0 +1,309 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// Play functions, animation, global header.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __P_LOCAL__
+#define __P_LOCAL__
+
+#ifndef __R_LOCAL__
+#include "r_local.h"
+#endif
+
+#define FLOATSPEED (FRACUNIT*5) // villsa [STRIFE] change to 5 (was 4)
+
+
+#define MAXHEALTH 100
+#define VIEWHEIGHT (41*FRACUNIT)
+
+// 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)
+
+
+// player radius for movement checking
+#define PLAYERRADIUS 16*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
+
+#define GRAVITY FRACUNIT
+#define MAXMOVE (30*FRACUNIT)
+
+#define USERANGE (64*FRACUNIT)
+#define MELEERANGE (64*FRACUNIT)
+#define PLAYERMELEERANGE (80*FRACUNIT) // haleyjd [STRIFE] New constant
+#define MISSILERANGE (32*64*FRACUNIT)
+
+// follow a player exlusively for 3 seconds
+#define BASETHRESHOLD 100
+
+
+
+//
+// P_TICK
+//
+
+// both the head and tail of the thinker list
+extern thinker_t thinkercap;
+
+
+void P_InitThinkers (void);
+void P_AddThinker (thinker_t* thinker);
+void P_RemoveThinker (thinker_t* thinker);
+
+
+//
+// P_PSPR
+//
+void P_SetupPsprites (player_t* curplayer);
+void P_MovePsprites (player_t* curplayer);
+void P_DropWeapon (player_t* player);
+
+
+//
+// P_USER
+//
+
+// haleyjd 09/15/10: externalized
+#define INVERSECOLORMAP 32
+
+void P_PlayerThink (player_t* player);
+// haleyjd 08/30/10: [STRIFE] Needed externally
+void P_Thrust (player_t* player, angle_t angle, fixed_t move);
+// villsa [STRIFE]
+char* P_RemoveInventoryItem(player_t *player, int slot, int amount);
+
+
+//
+// P_MOBJ
+//
+#define ONFLOORZ INT_MIN
+#define ONCEILINGZ INT_MAX
+
+// Time interval for item respawning.
+#define ITEMQUESIZE 128
+
+extern mapthing_t itemrespawnque[ITEMQUESIZE];
+extern int itemrespawntime[ITEMQUESIZE];
+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);
+mobj_t* P_SubstNullMobj (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);
+mobj_t* P_SpawnSparkPuff(fixed_t x, fixed_t y, fixed_t z); // villsa [STRIFE]
+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);
+mobj_t* P_SpawnFacingMissile(mobj_t* source, mobj_t* target, mobjtype_t type); // villsa [STRIFE]
+mobj_t* P_SpawnPlayerMissile(mobj_t* source, mobjtype_t type);
+mobj_t* P_SpawnMortar(mobj_t *source, mobjtype_t type); // villsa [STRIFE]
+void P_ExplodeMissile (mobj_t* mo); // villsa [STRIFE]
+
+
+//
+// P_ENEMY
+//
+void P_NoiseAlert (mobj_t* target, mobj_t* emmiter);
+void P_DoPunchAlert(mobj_t *puncher, mobj_t *punchee); // villsa [STRIFE]
+void A_BodyParts(mobj_t *actor); // haleyjd: [STRIFE]
+void A_AlertSpectreC(mobj_t* actor);
+void A_FaceTarget (mobj_t* actor);
+void P_FreePrisoners(void);
+void P_DestroyConverter(void);
+
+//
+// P_MAPUTL
+//
+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;
+
+// Extended MAXINTERCEPTS, to allow for intercepts overrun emulation.
+
+#define MAXINTERCEPTS_ORIGINAL 128
+#define MAXINTERCEPTS (MAXINTERCEPTS_ORIGINAL + 61)
+
+extern intercept_t intercepts[MAXINTERCEPTS];
+extern intercept_t* intercept_p;
+
+typedef boolean (*traverser_t) (intercept_t *in);
+
+fixed_t P_AproxDistance (fixed_t dx, fixed_t dy);
+int P_PointOnLineSide (fixed_t x, fixed_t y, line_t* line);
+int P_PointOnDivlineSide (fixed_t x, fixed_t y, divline_t* line);
+void P_MakeDivline (line_t* li, divline_t* dl);
+fixed_t P_InterceptVector (divline_t* v2, divline_t* v1);
+int P_BoxOnLineSide (fixed_t* tmbox, line_t* ld);
+
+extern fixed_t opentop;
+extern fixed_t openbottom;
+extern fixed_t openrange;
+extern fixed_t lowfloor;
+
+void P_LineOpening (line_t* linedef);
+
+boolean P_BlockLinesIterator (int x, int y, boolean(*func)(line_t*) );
+boolean P_BlockThingsIterator (int x, int y, boolean(*func)(mobj_t*) );
+
+#define PT_ADDLINES 1
+#define PT_ADDTHINGS 2
+#define PT_EARLYOUT 4
+
+extern divline_t trace;
+
+boolean
+P_PathTraverse
+( fixed_t x1,
+ fixed_t y1,
+ fixed_t x2,
+ fixed_t y2,
+ int flags,
+ boolean (*trav) (intercept_t *));
+
+void P_UnsetThingPosition (mobj_t* thing);
+void P_SetThingPosition (mobj_t* thing);
+
+
+//
+// P_MAP
+//
+
+// If "floatok" true, move would be ok
+// if within "tmfloorz - tmceilingz".
+extern boolean floatok;
+extern fixed_t tmfloorz;
+extern fixed_t tmceilingz;
+
+extern line_t *ceilingline;
+extern line_t *blockingline; // [STRIFE] New global
+
+boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y);
+boolean P_TryMove (mobj_t* thing, fixed_t x, fixed_t y);
+boolean P_CheckPositionZ(mobj_t* thing, fixed_t z); // villsa [STRIFE]
+boolean P_TeleportMove (mobj_t* thing, fixed_t x, fixed_t y);
+void P_SlideMove (mobj_t* mo);
+boolean P_CheckSight (mobj_t* t1, mobj_t* t2);
+void P_UseLines (player_t* player);
+
+boolean P_ChangeSector (sector_t* sector, boolean crunch);
+
+extern mobj_t* linetarget; // who got hit (or NULL)
+
+fixed_t
+P_AimLineAttack
+( mobj_t* t1,
+ angle_t angle,
+ fixed_t distance );
+
+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 );
+
+
+
+//
+// P_SETUP
+//
+extern byte* rejectmatrix; // for fast sight rejection
+extern short* blockmaplump; // offsets in blockmap are from here
+extern short* 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
+
+
+//
+// P_INTER
+//
+extern int maxammo[NUMAMMO];
+extern int clipammo[NUMAMMO];
+
+void
+P_TouchSpecialThing
+( mobj_t* special,
+ mobj_t* toucher );
+
+void
+P_DamageMobj
+( mobj_t* target,
+ mobj_t* inflictor,
+ mobj_t* source,
+ int damage );
+
+
+//
+// P_SPEC
+//
+#include "p_spec.h"
+
+
+#endif // __P_LOCAL__
diff --git a/src/strife/p_map.c b/src/strife/p_map.c
new file mode 100644
index 00000000..322e479b
--- /dev/null
+++ b/src/strife/p_map.c
@@ -0,0 +1,1655 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard, Andrey Budko
+//
+// 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 <stdio.h>
+#include <stdlib.h>
+
+#include "deh_misc.h"
+
+#include "m_bbox.h"
+#include "m_random.h"
+#include "i_system.h"
+
+#include "doomdef.h"
+#include "m_argv.h"
+#include "m_misc.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+// Data.
+#include "sounds.h"
+
+// Spechit overrun magic value.
+//
+// This is the value used by PrBoom-plus. I think the value below is
+// actually better and works with more demos. However, I think
+// it's better for the spechits emulation to be compatible with
+// PrBoom-plus, at least so that the big spechits emulation list
+// on Doomworld can also be used with Chocolate Doom.
+
+#define DEFAULT_SPECHIT_MAGIC 0x01C09C98
+
+// This is from a post by myk on the Doomworld forums,
+// outputted from entryway's spechit_magic generator for
+// s205n546.lmp. The _exact_ value of this isn't too
+// important; as long as it is in the right general
+// range, it will usually work. Otherwise, we can use
+// the generator (hacked doom2.exe) and provide it
+// with -spechit.
+
+//#define DEFAULT_SPECHIT_MAGIC 0x84f968e8
+
+
+fixed_t tmbbox[4];
+mobj_t* tmthing;
+int tmflags;
+fixed_t tmx;
+fixed_t tmy;
+
+
+// If "floatok" true, move would be ok
+// if within "tmfloorz - tmceilingz".
+boolean floatok;
+
+fixed_t tmfloorz;
+fixed_t tmceilingz;
+fixed_t tmdropoffz;
+
+// keep track of the line that lowers the ceiling,
+// so missiles don't explode against sky hack walls
+line_t* ceilingline;
+
+// haleyjd 20110203: [STRIFE] New global
+// "blockingline" tracks the linedef responsible for blocking motion of an mobj
+// for purposes of doing impact special activation by missiles. Suspiciously
+// similar to the solution used by Raven in Heretic and Hexen.
+line_t *blockingline;
+
+// keep track of special lines as they are hit,
+// but don't process them until the move is proven valid
+
+// fraggle: I have increased the size of this buffer. In the original Doom,
+// overrunning past this limit caused other bits of memory to be overwritten,
+// affecting demo playback. However, in doing so, the limit was still
+// exceeded. So we have to support more than 8 specials.
+//
+// We keep the original limit, to detect what variables in memory were
+// overwritten (see SpechitOverrun())
+
+#define MAXSPECIALCROSS 20
+#define MAXSPECIALCROSS_ORIGINAL 8
+
+line_t* spechit[MAXSPECIALCROSS];
+int numspechit;
+
+
+
+//
+// TELEPORT MOVE
+//
+
+//
+// PIT_StompThing
+//
+// [STRIFE] haleyjd 09/15/10: Modified so monsters can telestomp.
+//
+boolean PIT_StompThing (mobj_t* thing)
+{
+ fixed_t blockdist;
+
+ if (!(thing->flags & MF_SHOOTABLE) )
+ return true;
+
+ blockdist = thing->radius + tmthing->radius;
+
+ if ( abs(thing->x - tmx) >= blockdist
+ || abs(thing->y - tmy) >= blockdist )
+ {
+ // didn't hit it
+ return true;
+ }
+
+ // don't clip against self
+ if (thing == tmthing)
+ return true;
+
+ // [STRIFE] monsters DO stomp things, on all levels
+ // Basically, one thing involved must be a player.
+ // Monsters can telefrag players, and players can telefrag monsters, but
+ // monsters cannot telefrag other monsters.
+ if (!(tmthing->player || thing->player))
+ return false;
+
+ P_DamageMobj (thing, tmthing, tmthing, 10000);
+
+ return true;
+}
+
+
+//
+// P_TeleportMove
+//
+// [STRIFE]
+// haleyjd 09/15/10: Modified to set thing z position.
+//
+boolean P_TeleportMove(mobj_t* thing, fixed_t x, fixed_t y)
+{
+ int xl;
+ int xh;
+ int yl;
+ int yh;
+ int bx;
+ int by;
+
+ subsector_t* newsubsec;
+
+ // kill anything occupying the position
+ tmthing = thing;
+ tmflags = thing->flags;
+
+ 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 link the thing into its new position
+ P_UnsetThingPosition (thing);
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->x = x;
+ thing->y = y;
+ thing->z = tmfloorz; // haleyjd 09/15/10: [STRIFE] Rogue added a z-set here
+
+ P_SetThingPosition (thing);
+
+ return true;
+}
+
+
+//
+// MOVEMENT ITERATOR FUNCTIONS
+//
+
+static void SpechitOverrun(line_t *ld);
+
+//
+// PIT_CheckLine
+// Adjusts tmfloorz and tmceilingz as lines are contacted
+//
+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;
+
+ if (P_BoxOnLineSide (tmbbox, ld) != -1)
+ return true;
+
+ // 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.
+
+ if (!ld->backsector)
+ return false; // one sided line
+
+ if (!(tmthing->flags & MF_MISSILE) )
+ {
+ // villsa [STRIFE] include jumpover flag
+ if ( ld->flags & ML_BLOCKING &&
+ (!(ld->flags & ML_JUMPOVER) || tmfloorz + (32*FRACUNIT) > tmthing->z) )
+ return false; // explicitly blocking everything
+
+ // villsa [STRIFE] exclude floaters from blockmonster lines
+ if ( !tmthing->player && (ld->flags & ML_BLOCKMONSTERS) &&
+ !(tmthing->flags & MF_FLOAT))
+ return false; // block monsters only
+
+ // villsa [STRIFE]
+ if ( ld->flags & ML_BLOCKFLOATERS && tmthing->flags & MF_FLOAT )
+ return false; // block floaters only
+ }
+
+ // set openrange, opentop, openbottom
+ P_LineOpening (ld);
+
+ // adjust floor / ceiling heights
+ if (opentop < tmceilingz)
+ {
+ tmceilingz = opentop;
+ ceilingline = ld;
+ }
+
+ if (openbottom > tmfloorz)
+ tmfloorz = openbottom;
+
+ if (lowfloor < tmdropoffz)
+ tmdropoffz = lowfloor;
+
+ // if contacted a special line, add it to the list
+ if (ld->special)
+ {
+ spechit[numspechit] = ld;
+ numspechit++;
+
+ // fraggle: spechits overrun emulation code from prboom-plus
+ if (numspechit > MAXSPECIALCROSS_ORIGINAL)
+ {
+ SpechitOverrun(ld);
+ }
+ }
+
+ return true;
+}
+
+//
+// PIT_CheckThing
+//
+boolean PIT_CheckThing (mobj_t* thing)
+{
+ fixed_t blockdist;
+ boolean solid;
+ int damage;
+
+ if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) ))
+ return true;
+
+ // don't clip against self
+ if (thing == tmthing)
+ return true;
+
+ blockdist = thing->radius + tmthing->radius;
+
+ if ( abs(thing->x - tmx) >= blockdist
+ || abs(thing->y - tmy) >= blockdist )
+ {
+ // didn't hit it
+ return true;
+ }
+
+ // villsa [STRIFE] see if it went over / under
+ if(thing->height + thing->z < tmthing->z)
+ return true; // overhead
+
+ // villsa [STRIFE] see if it went over / under
+ if (tmthing->z + tmthing->height < thing->z)
+ return true; // underneath
+
+ // villsa [STRIFE] unused
+ // check for skulls slamming into things (removed)
+
+ // missiles can hit other things
+ if (tmthing->flags & MF_MISSILE)
+ {
+ // villsa [STRIFE] code to check over/under clipping moved to the beginning of the
+ // function, so that it applies to everything.
+
+ // villsa [STRIFE] updated to strife version
+ if (tmthing->target && (tmthing->target->type == thing->type))
+ {
+ // Don't hit same species as originator.
+ if (thing == tmthing->target)
+ return true;
+
+ // sdh: Add deh_species_infighting here. We can override the
+ // "monsters of the same species cant hurt each other" behavior
+ // through dehacked patches
+
+ if (thing->type != MT_PLAYER && !deh_species_infighting)
+ {
+ // Explode, but do no damage.
+ // Let players missile other players.
+ return false;
+ }
+ }
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ {
+ // didn't do any damage
+ return !(thing->flags & MF_SOLID);
+ }
+
+ // haleyjd 09/01/10: [STRIFE] Spectral check:
+ // Missiles cannot hit SPECTRAL entities unless the missiles are also
+ // flagged as SPECTRAL.
+ if (thing->flags & MF_SPECTRAL && !(tmthing->flags & MF_SPECTRAL))
+ return true; // keep going
+
+ // damage / explode
+ // haleyjd 09/01/10: [STRIFE] Modified missile damage formula
+ damage = ((P_Random()&3)+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)
+ {
+ solid = thing->flags&MF_SOLID;
+ if (tmthing->player) // villsa [STRIFE] no longer checks MF_PICKUP flag
+ {
+ // can remove thing
+ P_TouchSpecialThing (thing, tmthing);
+ }
+ return !solid;
+ }
+
+ return !(thing->flags & MF_SOLID);
+}
+
+
+//
+// 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
+//
+// haleyjd 20110203:
+// [STRIFE] Modified to clear blockingline in advance of P_BlockLinesIterator
+//
+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;
+ tmflags = thing->flags;
+
+ 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);
+
+ // [STRIFE] clear blockingline (see P_XYMovement, P_BlockLinesIterator)
+ blockingline = NULL;
+ 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;
+
+ if ( tmflags & 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;
+
+ 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 )
+{
+ fixed_t oldx;
+ fixed_t oldy;
+ int side;
+ int oldside;
+ line_t* ld;
+
+ floatok = false;
+ if (!P_CheckPosition (thing, x, y))
+ return false; // solid wall or thing
+
+ if ( !(thing->flags & MF_NOCLIP) )
+ {
+ if (tmceilingz - tmfloorz < thing->height)
+ return false; // doesn't fit
+
+ floatok = true;
+
+ // villsa [STRIFE] Removed MF_TELEPORT
+ if (tmceilingz - thing->z < thing->height)
+ return false; // mobj must lower itself to fit
+
+ // villsa [STRIFE] non-robots are limited to 16 unit step height
+ if ((thing->flags & MF_NOBLOOD) == 0 && tmfloorz - thing->z > (16*FRACUNIT))
+ return false;
+ if (tmfloorz - thing->z > 24*FRACUNIT)
+ return false; // too big a step up
+
+ // villsa [STRIFE] special case for missiles
+ if((thing->flags & MF_MISSILE) && tmfloorz - thing->z > 4*FRACUNIT)
+ return false;
+
+ // haleyjd 20110204 [STRIFE]: dropoff height changed 24 -> 32
+ if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT))
+ && tmfloorz - tmdropoffz > 32*FRACUNIT )
+ return false; // don't stand over a dropoff
+ }
+
+ // the move is ok,
+ // so link the thing into its new position
+ P_UnsetThingPosition (thing);
+
+ oldx = thing->x;
+ oldy = thing->y;
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+ thing->x = x;
+ thing->y = y;
+
+ P_SetThingPosition (thing);
+
+ // if any special lines were hit, do the effect
+ if (! (thing->flags&MF_NOCLIP) ) // villsa [STRIFE] MF_TELEPORT not used
+ {
+ while (numspechit--)
+ {
+ // see if the line was crossed
+ ld = spechit[numspechit];
+ side = P_PointOnLineSide (thing->x, thing->y, ld);
+ oldside = P_PointOnLineSide (oldx, oldy, ld);
+ if (side != oldside)
+ {
+ if (ld->special)
+ P_CrossSpecialLine (ld-lines, oldside, thing);
+ }
+ }
+ }
+
+ return true;
+}
+
+//
+// P_CheckPositionZ
+//
+// villsa [STRIFE] new function
+// Check colliding things on top of one another; ie., 3D Object Clipping
+//
+boolean P_CheckPositionZ(mobj_t* thing, fixed_t height)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ int xl;
+ int xh;
+ int yl;
+ int yh;
+ int bx;
+ int by;
+ subsector_t* newsubsec;
+
+ x = thing->x;
+ y = thing->y;
+ z = thing->z;
+
+ thing->z = height;
+
+ tmthing = thing;
+ tmflags = thing->flags;
+ tmx = x;
+ tmy = y;
+
+ tmbbox[BOXTOP] = y + tmthing->radius;
+ tmbbox[BOXBOTTOM] = y - tmthing->radius;
+ tmbbox[BOXRIGHT] = x + tmthing->radius;
+ tmbbox[BOXLEFT] = x - tmthing->radius;
+
+ ceilingline = 0;
+ newsubsec = thing->subsector;
+
+ // 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;
+
+ if(tmflags & 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))
+ {
+ tmthing->z = z;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+//
+// 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.
+//
+// [STRIFE] Verified unmodified
+//
+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?
+
+ thing->floorz = tmfloorz;
+ thing->ceilingz = tmceilingz;
+
+ if (onfloor)
+ {
+ // walking monsters rise and fall with the floor
+ thing->z = thing->floorz;
+ }
+ else
+ {
+ // don't adjust a floating monster unless forced to
+ if (thing->z+thing->height > thing->ceilingz)
+ thing->z = thing->ceilingz - thing->height;
+ }
+
+ if (thing->ceilingz - thing->floorz < thing->height)
+ return false;
+
+ return true;
+}
+
+
+
+//
+// SLIDE MOVE
+// Allows the player to slide along any angled walls.
+//
+fixed_t bestslidefrac;
+fixed_t secondslidefrac;
+
+line_t* bestslideline;
+line_t* secondslideline;
+
+mobj_t* slidemo;
+
+fixed_t tmxmove;
+fixed_t tmymove;
+
+
+
+//
+// P_HitSlideLine
+// Adjusts the xmove / ymove
+// so that the next move will slide along the wall.
+//
+// [STRIFE] Verified unmodified
+//
+void P_HitSlideLine (line_t* ld)
+{
+ int side;
+
+ angle_t lineangle;
+ angle_t moveangle;
+ angle_t deltaangle;
+
+ fixed_t movelen;
+ fixed_t newlen;
+
+
+ if (ld->slopetype == ST_HORIZONTAL)
+ {
+ tmymove = 0;
+ return;
+ }
+
+ if (ld->slopetype == ST_VERTICAL)
+ {
+ tmxmove = 0;
+ return;
+ }
+
+ 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);
+ deltaangle = moveangle-lineangle;
+
+ if (deltaangle > ANG180)
+ deltaangle += ANG180;
+ // I_Error ("SlideLine: ang>ANG180");
+
+ lineangle >>= ANGLETOFINESHIFT;
+ deltaangle >>= ANGLETOFINESHIFT;
+
+ movelen = P_AproxDistance (tmxmove, tmymove);
+ newlen = FixedMul (movelen, finecosine[deltaangle]);
+
+ tmxmove = FixedMul (newlen, finecosine[lineangle]);
+ tmymove = FixedMul (newlen, finesine[lineangle]);
+}
+
+
+//
+// PTR_SlideTraverse
+//
+// [STRIFE] Modified for smaller step-up height
+//
+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))
+ {
+ // don't hit the back side
+ return true;
+ }
+ goto isblocking;
+ }
+
+ // set openrange, opentop, openbottom
+ P_LineOpening (li);
+
+ if (openrange < slidemo->height)
+ goto isblocking; // doesn't fit
+
+ if (opentop - slidemo->z < slidemo->height)
+ goto isblocking; // mobj is too high
+
+ // villsa [STRIFE] change from 24 to 16
+ if (openbottom - slidemo->z > 16*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.
+//
+// [STRIFE] Verified unmodified
+//
+void P_SlideMove (mobj_t* mo)
+{
+ fixed_t leadx;
+ fixed_t leady;
+ fixed_t trailx;
+ fixed_t traily;
+ fixed_t newx;
+ fixed_t newy;
+ int hitcount;
+
+ slidemo = mo;
+ hitcount = 0;
+
+retry:
+ if (++hitcount == 3)
+ 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 most have hit the middle, so stairstep
+stairstep:
+ if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
+ P_TryMove (mo, mo->x + mo->momx, mo->y);
+ return;
+ }
+
+ // fudge a bit to make sure it doesn't hit
+ bestslidefrac -= 0x800;
+ if (bestslidefrac > 0)
+ {
+ newx = FixedMul (mo->momx, bestslidefrac);
+ newy = FixedMul (mo->momy, bestslidefrac);
+
+ if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
+ goto stairstep;
+ }
+
+ // Now continue along the wall.
+ // First calculate remainder.
+ bestslidefrac = FRACUNIT-(bestslidefrac+0x800);
+
+ if (bestslidefrac > FRACUNIT)
+ bestslidefrac = FRACUNIT;
+
+ if (bestslidefrac <= 0)
+ return;
+
+ tmxmove = FixedMul (mo->momx, bestslidefrac);
+ tmymove = FixedMul (mo->momy, bestslidefrac);
+
+ P_HitSlideLine (bestslideline); // clip the moves
+
+ mo->momx = tmxmove;
+ mo->momy = tmymove;
+
+ if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
+ {
+ goto retry;
+ }
+}
+
+
+//
+// P_LineAttack
+//
+mobj_t* linetarget; // who got hit (or NULL)
+mobj_t* shootthing;
+
+// Height if not aiming up or down
+// ???: use slope for monsters?
+fixed_t shootz;
+
+int la_damage;
+fixed_t attackrange;
+
+fixed_t aimslope;
+
+// slopes to top and bottom of target
+extern fixed_t topslope;
+extern fixed_t bottomslope;
+
+
+//
+// PTR_AimTraverse
+// Sets linetaget and aimslope when a target is aimed at.
+//
+// [STRIFE] Verified unmodified
+//
+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);
+
+ // Return false if there is no back sector. This should never
+ // be the case if the line is two-sided; however, some WADs
+ // (eg. ottawau.wad) use this as an "impassible glass" trick
+ // and rely on Vanilla Doom's (unintentional) support for this.
+
+ if (li->backsector == NULL)
+ {
+ return false;
+ }
+
+ 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
+
+ // 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
+//
+// [STRIFE] Changes for Spectres and Mauler puff/damage inflictor
+//
+boolean PTR_ShootTraverse (intercept_t* in)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ fixed_t frac;
+
+ line_t* li;
+
+ mobj_t* th;
+ mobj_t* th2; // villsa [STRIFE]
+
+ fixed_t slope;
+ fixed_t dist;
+ fixed_t thingtopslope;
+ fixed_t thingbottomslope;
+
+ if (in->isaline)
+ {
+ li = in->d.line;
+
+ if (li->special)
+ P_ShootSpecialLine (shootthing, li);
+
+ if ( !(li->flags & ML_TWOSIDED) )
+ goto hitline;
+
+ // crosses a two sided line
+ P_LineOpening (li);
+
+ dist = FixedMul (attackrange, in->frac);
+
+ // Check if backsector is NULL. See comment in PTR_AimTraverse.
+
+ if (li->backsector == NULL)
+ {
+ goto hitline;
+ }
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
+ {
+ slope = FixedDiv (openbottom - shootz , dist);
+ if (slope > aimslope)
+ goto hitline;
+ }
+
+ if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
+ {
+ slope = FixedDiv (opentop - shootz , dist);
+ if (slope < aimslope)
+ goto hitline;
+ }
+
+ // shot continues
+ return true;
+
+
+ // hit line
+hitline:
+ // 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)
+ return false;
+ }
+
+ // villsa [STRIFE]
+ if(la_damage > 0)
+ {
+ // villsa [STRIFE] Test against Mauler attack range
+ if(attackrange != 2112*FRACUNIT)
+ P_SpawnPuff(x, y, z); // Spawn bullet puffs.
+ else
+ P_SpawnMobj(x, y, z, MT_STRIFEPUFF3);
+ }
+
+ // 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
+
+ // haleyjd 09/18/10: [STRIFE] Corrected - not MVIS, but SPECTRAL.
+ if(th->flags & MF_SPECTRAL)
+ return true; // is a spectral entity
+
+ // 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));
+
+ // villsa [STRIFE] Check for Mauler attack range
+ if(attackrange == 2112*FRACUNIT)
+ {
+ th2 = P_SpawnMobj(x, y, z, MT_STRIFEPUFF3);
+ th2->momz = -FRACUNIT;
+ P_DamageMobj(th, th2, shootthing, la_damage);
+ return false;
+ }
+
+ // villsa [STRIFE] disabled check for damage
+ //if (la_damage)
+ P_DamageMobj (th, shootthing, shootthing, la_damage);
+
+ // Spawn bullet puffs or blod spots,
+ // depending on target type.
+ if (in->d.thing->flags & MF_NOBLOOD)
+ P_SpawnSparkPuff(x, y, z); // villsa [STRIFE] call spark puff function instead
+ else
+ P_SpawnBlood (x,y,z, la_damage);
+
+ // don't go any farther
+ return false;
+
+}
+
+
+//
+// P_AimLineAttack
+//
+// [STRIFE] Modified to support player->pitch
+//
+fixed_t
+P_AimLineAttack
+( mobj_t* t1,
+ angle_t angle,
+ fixed_t distance )
+{
+ fixed_t x2;
+ fixed_t y2;
+
+ t1 = P_SubstNullMobj(t1);
+
+ 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;
+
+ P_PathTraverse ( t1->x, t1->y,
+ x2, y2,
+ PT_ADDLINES|PT_ADDTHINGS,
+ PTR_AimTraverse );
+
+ if (linetarget)
+ return aimslope;
+ else // villsa [STRIFE] checks for player pitch
+ {
+ if(t1->player)
+ return (t1->player->pitch << FRACBITS) / 160;
+ }
+
+ return 0;
+}
+
+
+//
+// P_LineAttack
+// If damage == 0, it is just a test trace
+// that will leave linetarget set.
+//
+// [STRIFE] Modified to check lines only if damage <= 0 (see P_RadiusAttack)
+//
+void
+P_LineAttack
+( mobj_t* t1,
+ angle_t angle,
+ fixed_t distance,
+ fixed_t slope,
+ int damage )
+{
+ fixed_t x2;
+ fixed_t y2;
+ int traverseflags;
+
+ 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;
+
+ // villsa [STRIFE] test lines only if damage is <= 0
+ if(damage >= 1)
+ traverseflags = (PT_ADDLINES|PT_ADDTHINGS);
+ else
+ traverseflags = PT_ADDLINES;
+
+ P_PathTraverse(t1->x, t1->y,
+ x2, y2,
+ traverseflags,
+ PTR_ShootTraverse);
+}
+
+
+
+//
+// USE LINES
+//
+// [STRIFE] Verified unmodified
+//
+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);
+
+ // can't use for than one special line in a row
+ return false;
+}
+
+
+//
+// P_UseLines
+// Looks for special lines in front of the player to activate.
+//
+// [STRIFE] Verified unmodified
+//
+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];
+
+ P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
+}
+
+
+//
+// RADIUS ATTACK
+//
+mobj_t* bombsource;
+mobj_t* bombspot;
+int bombdamage;
+
+
+//
+// PIT_RadiusAttack
+// "bombsource" is the creature
+// that caused the explosion at "bombspot".
+//
+// [STRIFE] Modified for Spectral and Inquisitor exclusions
+//
+boolean PIT_RadiusAttack (mobj_t* thing)
+{
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t dist;
+
+ if (!(thing->flags & MF_SHOOTABLE))
+ return true;
+
+ // haleyjd 10/04/10: Spectrals are not damaged by blast radii
+ if(thing->flags & MF_SPECTRAL)
+ return true;
+
+ // Boss spider and cyborg
+ // take no damage from concussion.
+ // villsa [STRIFE] unused
+ // - haleyjd: INQUISITOR
+
+ if(thing->type == MT_INQUISITOR)
+ return true;
+
+ dx = abs(thing->x - bombspot->x);
+ dy = 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.
+//
+// [STRIFE] Modified to emit "test" tracers which can shatter glass screens
+// and windows.
+//
+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 );
+
+ // villsa [STRIFE] Send out 0 damage tracers to shatter nearby glass.
+ spot->z += 32*FRACUNIT;
+ P_LineAttack(spot, 0, dist, 1, 0);
+ P_LineAttack(spot, ANG90, dist, 1, 0);
+ P_LineAttack(spot, ANG180, dist, 1, 0);
+ P_LineAttack(spot, ANG270, dist, 1, 0);
+ spot->z -= 32*FRACUNIT;
+}
+
+
+
+//
+// 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.
+//
+boolean crushchange;
+boolean nofit;
+
+
+//
+// PIT_ChangeSector
+//
+// [STRIFE] Changes to crushing behavior
+//
+boolean PIT_ChangeSector (mobj_t* thing)
+{
+ mobj_t* mo;
+
+ if (P_ThingHeightClip (thing))
+ {
+ // keep checking
+ return true;
+ }
+
+ // crunch bodies to giblets
+ if (thing->health <= 0)
+ {
+ // villsa [STRIFE] do something with the player
+ if(thing->player && thing->subsector->sector->specialdata)
+ {
+ nofit = true;
+ return false;
+ }
+ //P_SetMobjState (thing, S_GIBS); // villsa [STRIFE] unused
+
+ A_BodyParts(thing); // villsa [STRIFE] spit out meat/junk stuff
+ thing->flags &= ~MF_SOLID;
+ thing->height = 0;
+ thing->radius = 0;
+
+ // keep checking
+ return true;
+ }
+
+ // crunch dropped items
+ if (thing->flags & MF_DROPPED)
+ {
+ P_RemoveMobj (thing);
+
+ // keep checking
+ return true;
+ }
+
+ if (! (thing->flags & MF_SHOOTABLE) )
+ {
+ // assume it is bloody gibs or something
+ return true;
+ }
+
+ nofit = true;
+
+ if (crushchange && !(leveltime&3) )
+ {
+ int t;
+ S_StartSound(thing, sfx_pcrush); // villsa [STRIFE]
+ 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_DEATH);
+
+ t = P_Random();
+ mo->momx = (t - P_Random ()) << 12;
+ t = P_Random();
+ mo->momy = (t - P_Random ()) << 12;
+ }
+
+ // keep checking (crush other things)
+ return true;
+}
+
+
+
+//
+// P_ChangeSector
+//
+// [STRIFE] Verified unmodified
+//
+boolean
+P_ChangeSector
+( sector_t* sector,
+ boolean crunch )
+{
+ int x;
+ int y;
+
+ nofit = false;
+ crushchange = crunch;
+
+ // 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;
+}
+
+// Code to emulate the behavior of Vanilla Doom when encountering an overrun
+// of the spechit array. This is by Andrey Budko (e6y) and comes from his
+// PrBoom plus port. A big thanks to Andrey for this.
+
+static void SpechitOverrun(line_t *ld)
+{
+ static unsigned int baseaddr = 0;
+ unsigned int addr;
+
+ if (baseaddr == 0)
+ {
+ int p;
+
+ // This is the first time we have had an overrun. Work out
+ // what base address we are going to use.
+ // Allow a spechit value to be specified on the command line.
+
+ //!
+ // @category compat
+ // @arg <n>
+ //
+ // Use the specified magic value when emulating spechit overruns.
+ //
+
+ p = M_CheckParmWithArgs("-spechit", 1);
+
+ if (p > 0)
+ {
+ M_StrToInt(myargv[p+1], (int *) &baseaddr);
+ }
+ else
+ {
+ baseaddr = DEFAULT_SPECHIT_MAGIC;
+ }
+ }
+
+ // Calculate address used in doom2.exe
+
+ addr = baseaddr + (ld - lines) * 0x3E;
+
+ switch(numspechit)
+ {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ tmbbox[numspechit-9] = addr;
+ break;
+ case 13:
+ nofit = addr; // haleyjd 20110204: nofit/crushchange are in opposite
+ break; // order in the Strife binary.
+ case 14:
+ crushchange = addr;
+ break;
+ default:
+ fprintf(stderr, "SpechitOverrun: Warning: unable to emulate"
+ "an overrun where numspechit=%i\n",
+ numspechit);
+ break;
+ }
+}
+
diff --git a/src/strife/p_maputl.c b/src/strife/p_maputl.c
new file mode 100644
index 00000000..ee8485ca
--- /dev/null
+++ b/src/strife/p_maputl.c
@@ -0,0 +1,1061 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+// Copyright(C) 2005, 2006 Andrey Budko
+//
+// 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 <stdlib.h>
+
+
+#include "m_bbox.h"
+
+#include "doomdef.h"
+#include "doomstat.h"
+#include "p_local.h"
+
+
+// State.
+#include "r_state.h"
+
+//
+// P_AproxDistance
+// Gives an estimation of distance (not exact)
+//
+// [STRIFE] Verified unmodified
+//
+fixed_t
+P_AproxDistance
+( fixed_t dx,
+ fixed_t dy )
+{
+ dx = abs(dx);
+ dy = abs(dy);
+ if (dx < dy)
+ return dx+dy-(dx>>1);
+ return dx+dy-(dy>>1);
+}
+
+
+//
+// P_PointOnLineSide
+// Returns 0 or 1
+//
+// [STRIFE] Verified unmodified
+//
+int
+P_PointOnLineSide
+( fixed_t x,
+ fixed_t y,
+ line_t* line )
+{
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t left;
+ fixed_t right;
+
+ if (!line->dx)
+ {
+ if (x <= line->v1->x)
+ return line->dy > 0;
+
+ return line->dy < 0;
+ }
+ if (!line->dy)
+ {
+ if (y <= line->v1->y)
+ return line->dx < 0;
+
+ return line->dx > 0;
+ }
+
+ dx = (x - line->v1->x);
+ dy = (y - line->v1->y);
+
+ left = FixedMul ( line->dy>>FRACBITS , dx );
+ right = FixedMul ( dy , line->dx>>FRACBITS );
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+
+//
+// P_BoxOnLineSide
+// Considers the line to be infinite
+// Returns side 0 or 1, -1 if box crosses the line.
+//
+// [STRIFE] Verified unmodified
+//
+int
+P_BoxOnLineSide
+( fixed_t* tmbox,
+ line_t* ld )
+{
+ int p1 = 0;
+ int p2 = 0;
+
+ switch (ld->slopetype)
+ {
+ case ST_HORIZONTAL:
+ p1 = tmbox[BOXTOP] > ld->v1->y;
+ p2 = tmbox[BOXBOTTOM] > ld->v1->y;
+ if (ld->dx < 0)
+ {
+ p1 ^= 1;
+ p2 ^= 1;
+ }
+ break;
+
+ case ST_VERTICAL:
+ p1 = tmbox[BOXRIGHT] < ld->v1->x;
+ p2 = tmbox[BOXLEFT] < ld->v1->x;
+ if (ld->dy < 0)
+ {
+ p1 ^= 1;
+ p2 ^= 1;
+ }
+ break;
+
+ case ST_POSITIVE:
+ p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
+ p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
+ break;
+
+ case ST_NEGATIVE:
+ p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
+ p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
+ break;
+ }
+
+ if (p1 == p2)
+ return p1;
+ return -1;
+}
+
+
+//
+// P_PointOnDivlineSide
+// Returns 0 or 1.
+//
+// [STRIFE] Verified unmodified
+//
+int
+P_PointOnDivlineSide
+( fixed_t x,
+ fixed_t y,
+ divline_t* line )
+{
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t left;
+ fixed_t right;
+
+ if (!line->dx)
+ {
+ if (x <= line->x)
+ return line->dy > 0;
+
+ return line->dy < 0;
+ }
+ if (!line->dy)
+ {
+ if (y <= line->y)
+ return line->dx < 0;
+
+ return line->dx > 0;
+ }
+
+ dx = (x - line->x);
+ dy = (y - line->y);
+
+ // try to quickly decide by looking at sign bits
+ if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 )
+ {
+ if ( (line->dy ^ dx) & 0x80000000 )
+ return 1; // (left is negative)
+ return 0;
+ }
+
+ left = FixedMul ( line->dy>>8, dx>>8 );
+ right = FixedMul ( dy>>8 , line->dx>>8 );
+
+ if (right < left)
+ return 0; // front side
+ return 1; // back side
+}
+
+
+
+//
+// P_MakeDivline
+//
+void
+P_MakeDivline
+( 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.
+//
+// [STRIFE] Verified unmodified
+//
+fixed_t
+P_InterceptVector
+( divline_t* v2,
+ divline_t* v1 )
+{
+#if 1
+ fixed_t frac;
+ fixed_t num;
+ fixed_t den;
+
+ den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy);
+
+ if (den == 0)
+ return 0;
+ // I_Error ("P_InterceptVector: parallel");
+
+ num =
+ FixedMul ( (v1->x - v2->x)>>8 ,v1->dy )
+ +FixedMul ( (v2->y - v1->y)>>8, v1->dx );
+
+ frac = FixedDiv (num , den);
+
+ return frac;
+#else // UNUSED, float debug.
+ float frac;
+ float num;
+ float den;
+ float v1x;
+ float v1y;
+ float v1dx;
+ float v1dy;
+ float v2x;
+ float v2y;
+ float v2dx;
+ float v2dy;
+
+ v1x = (float)v1->x/FRACUNIT;
+ v1y = (float)v1->y/FRACUNIT;
+ v1dx = (float)v1->dx/FRACUNIT;
+ v1dy = (float)v1->dy/FRACUNIT;
+ v2x = (float)v2->x/FRACUNIT;
+ v2y = (float)v2->y/FRACUNIT;
+ v2dx = (float)v2->dx/FRACUNIT;
+ v2dy = (float)v2->dy/FRACUNIT;
+
+ den = v1dy*v2dx - v1dx*v2dy;
+
+ if (den == 0)
+ return 0; // parallel
+
+ num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
+ frac = num / den;
+
+ return frac*FRACUNIT;
+#endif
+}
+
+
+//
+// P_LineOpening
+// Sets opentop and openbottom to the window
+// through a two sided line.
+// OPTIMIZE: keep this precalculated
+//
+// [STRIFE] Verified unmodified
+//
+fixed_t opentop;
+fixed_t openbottom;
+fixed_t openrange;
+fixed_t lowfloor;
+
+
+void P_LineOpening (line_t* linedef)
+{
+ sector_t* front;
+ sector_t* back;
+
+ if (linedef->sidenum[1] == -1)
+ {
+ // single sided line
+ openrange = 0;
+ return;
+ }
+
+ front = linedef->frontsector;
+ back = linedef->backsector;
+
+ if (front->ceilingheight < back->ceilingheight)
+ opentop = front->ceilingheight;
+ else
+ opentop = back->ceilingheight;
+
+ if (front->floorheight > back->floorheight)
+ {
+ openbottom = front->floorheight;
+ lowfloor = back->floorheight;
+ }
+ else
+ {
+ openbottom = back->floorheight;
+ lowfloor = front->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.
+//
+// [STRIFE] Verified unmodified
+//
+void P_UnsetThingPosition (mobj_t* thing)
+{
+ int blockx;
+ int blocky;
+
+ if ( ! (thing->flags & MF_NOSECTOR) )
+ {
+ // inert things don't need to be in blockmap?
+ // unlink from subsector
+ if (thing->snext)
+ thing->snext->sprev = thing->sprev;
+
+ if (thing->sprev)
+ thing->sprev->snext = thing->snext;
+ else
+ thing->subsector->sector->thinglist = thing->snext;
+ }
+
+ if ( ! (thing->flags & MF_NOBLOCKMAP) )
+ {
+ // inert things don't need to be in blockmap
+ // unlink from block map
+ if (thing->bnext)
+ thing->bnext->bprev = thing->bprev;
+
+ if (thing->bprev)
+ thing->bprev->bnext = thing->bnext;
+ else
+ {
+ blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
+ blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
+
+ if (blockx>=0 && blockx < bmapwidth
+ && blocky>=0 && blocky <bmapheight)
+ {
+ blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
+ }
+ }
+ }
+}
+
+
+//
+// P_SetThingPosition
+// Links a thing into both a block and a subsector
+// based on it's x y.
+// Sets thing->subsector properly
+//
+// [STRIFE] Verified unmodified
+//
+void
+P_SetThingPosition (mobj_t* thing)
+{
+ subsector_t* ss;
+ sector_t* sec;
+ int blockx;
+ int blocky;
+ mobj_t** link;
+
+
+ // link into subsector
+ ss = R_PointInSubsector (thing->x,thing->y);
+ thing->subsector = ss;
+
+ if ( ! (thing->flags & MF_NOSECTOR) )
+ {
+ // invisible things don't go into the sector links
+ sec = ss->sector;
+
+ thing->sprev = NULL;
+ thing->snext = sec->thinglist;
+
+ if (sec->thinglist)
+ sec->thinglist->sprev = thing;
+
+ sec->thinglist = thing;
+ }
+
+
+ // link into blockmap
+ if ( ! (thing->flags & MF_NOBLOCKMAP) )
+ {
+ // inert things don't need to be in blockmap
+ blockx = (thing->x - bmaporgx)>>MAPBLOCKSHIFT;
+ blocky = (thing->y - bmaporgy)>>MAPBLOCKSHIFT;
+
+ if (blockx>=0
+ && blockx < bmapwidth
+ && blocky>=0
+ && blocky < bmapheight)
+ {
+ link = &blocklinks[blocky*bmapwidth+blockx];
+ thing->bprev = NULL;
+ thing->bnext = *link;
+ if (*link)
+ (*link)->bprev = thing;
+
+ *link = thing;
+ }
+ else
+ {
+ // thing is off the map
+ thing->bnext = thing->bprev = NULL;
+ }
+ }
+}
+
+
+
+//
+// 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.
+//
+// haleyjd 20110203:
+// [STRIFE] Modified to track blockingline
+//
+boolean
+P_BlockLinesIterator
+( int x,
+ int y,
+ boolean(*func)(line_t*) )
+{
+ int offset;
+ short* list;
+ line_t* ld;
+
+ if (x<0
+ || y<0
+ || x>=bmapwidth
+ || y>=bmapheight)
+ {
+ return true;
+ }
+
+ offset = y*bmapwidth+x;
+
+ offset = *(blockmap+offset);
+
+ for ( list = blockmaplump+offset ; *list != -1 ; list++)
+ {
+ ld = &lines[*list];
+
+ // [STRIFE]: set blockingline (see P_XYMovement @ p_mobj.c)
+ blockingline = ld;
+
+ 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
+//
+// [STRIFE] Verified unmodified
+//
+boolean
+P_BlockThingsIterator
+( int x,
+ int y,
+ boolean(*func)(mobj_t*) )
+{
+ mobj_t* mobj;
+
+ if ( x<0
+ || y<0
+ || x>=bmapwidth
+ || y>=bmapheight)
+ {
+ return true;
+ }
+
+
+ for (mobj = blocklinks[y*bmapwidth+x] ;
+ mobj ;
+ mobj = mobj->bnext)
+ {
+ if (!func( mobj ) )
+ return false;
+ }
+ return true;
+}
+
+
+
+//
+// INTERCEPT ROUTINES
+//
+intercept_t intercepts[MAXINTERCEPTS];
+intercept_t* intercept_p;
+
+divline_t trace;
+boolean earlyout;
+int ptflags;
+
+static void InterceptsOverrun(int num_intercepts, intercept_t *intercept);
+
+//
+// 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.
+// Returns true if earlyout and a solid line hit.
+//
+// haleyjd 20110204 [STRIFE]: Added Rogue's fix for intercepts overflows
+//
+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
+
+ // try to early out the check
+ if (earlyout
+ && frac < FRACUNIT
+ && !ld->backsector)
+ {
+ return false; // stop checking
+ }
+
+
+ intercept_p->frac = frac;
+ intercept_p->isaline = true;
+ intercept_p->d.line = ld;
+ intercept_p++;
+
+ // haleyjd 20110204 [STRIFE]
+ // Evidently Rogue had trouble with intercepts overflows during
+ // development, as they added this check here which will stop adding
+ // intercepts if the array would be overflown.
+ if(intercept_p <= &intercepts[MAXINTERCEPTS_ORIGINAL-2])
+ return true; // continue
+ else
+ return false;
+
+ // [STRIFE] Not needed?
+ //InterceptsOverrun(intercept_p - intercepts, intercept_p);
+}
+
+
+
+//
+// PIT_AddThingIntercepts
+//
+boolean PIT_AddThingIntercepts (mobj_t* thing)
+{
+ fixed_t x1;
+ fixed_t y1;
+ fixed_t x2;
+ fixed_t y2;
+
+ int s1;
+ int s2;
+
+ boolean tracepositive;
+
+ divline_t dl;
+
+ fixed_t frac;
+
+ tracepositive = (trace.dx ^ trace.dy)>0;
+
+ // check a corner to corner crossection for hit
+ if (tracepositive)
+ {
+ 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
+
+ intercept_p->frac = frac;
+ intercept_p->isaline = false;
+ intercept_p->d.thing = thing;
+
+ intercept_p++;
+
+ // haleyjd 20110204 [STRIFE]: As above, protection against intercepts
+ // overflows, courtesy of Rogue Software.
+ if(intercept_p <= &intercepts[MAXINTERCEPTS_ORIGINAL-2])
+ return true; // keep going
+ else
+ return false;
+
+ // haleyjd [STRIFE]: Not needed?
+ //InterceptsOverrun(intercept_p - intercepts, intercept_p);
+}
+
+
+//
+// P_TraverseIntercepts
+// Returns true if the traverser function returns true
+// for all lines.
+//
+// [STRIFE] Verified unmodified.
+//
+boolean
+P_TraverseIntercepts
+( traverser_t func,
+ fixed_t maxfrac )
+{
+ int count;
+ fixed_t dist;
+ intercept_t* scan;
+ intercept_t* in;
+
+ count = intercept_p - intercepts;
+
+ in = 0; // shut up compiler warning
+
+ while (count--)
+ {
+ dist = INT_MAX;
+ for (scan = intercepts ; scan<intercept_p ; scan++)
+ {
+ if (scan->frac < dist)
+ {
+ dist = scan->frac;
+ in = scan;
+ }
+ }
+
+ if (dist > maxfrac)
+ return true; // checked everything in range
+
+#if 0 // UNUSED
+ {
+ // don't check these yet, there may be others inserted
+ in = scan = intercepts;
+ for ( scan = intercepts ; scan<intercept_p ; scan++)
+ if (scan->frac > maxfrac)
+ *in++ = *scan;
+ intercept_p = in;
+ return false;
+ }
+#endif
+
+ if ( !func (in) )
+ return false; // don't bother going farther
+
+ in->frac = INT_MAX;
+ }
+
+ return true; // everything was traversed
+}
+
+extern fixed_t bulletslope;
+
+// Intercepts Overrun emulation, from PrBoom-plus.
+// Thanks to Andrey Budko (entryway) for researching this and his
+// implementation of Intercepts Overrun emulation in PrBoom-plus
+// which this is based on.
+
+typedef struct
+{
+ int len;
+ void *addr;
+ boolean int16_array;
+} intercepts_overrun_t;
+
+// Intercepts memory table. This is where various variables are located
+// in memory in Vanilla Doom. When the intercepts table overflows, we
+// need to write to them.
+//
+// Almost all of the values to overwrite are 32-bit integers, except for
+// playerstarts, which is effectively an array of 16-bit integers and
+// must be treated differently.
+
+// haleyjd 20110204: NB: This array has *not* been updated for Strife,
+// because Strife has protection against intercepts overflows. The memory
+// layout of the 1.2 and 1.31 EXEs is radically different with respect
+// to this area of the BSS segment, so it would have to be redone entirely
+// if it were needed.
+
+static intercepts_overrun_t intercepts_overrun[] =
+{
+ {4, NULL, false},
+ {4, NULL, /* &earlyout, */ false},
+ {4, NULL, /* &intercept_p, */ false},
+ {4, &lowfloor, false},
+ {4, &openbottom, false},
+ {4, &opentop, false},
+ {4, &openrange, false},
+ {4, NULL, false},
+ {120, NULL, /* &activeplats, */ false},
+ {8, NULL, false},
+ {4, &bulletslope, false},
+ {4, NULL, /* &swingx, */ false},
+ {4, NULL, /* &swingy, */ false},
+ {4, NULL, false},
+ {40, &playerstarts, true},
+ {4, NULL, /* &blocklinks, */ false},
+ {4, &bmapwidth, false},
+ {4, NULL, /* &blockmap, */ false},
+ {4, &bmaporgx, false},
+ {4, &bmaporgy, false},
+ {4, NULL, /* &blockmaplump, */ false},
+ {4, &bmapheight, false},
+ {0, NULL, false},
+};
+
+// Overwrite a specific memory location with a value.
+
+static void InterceptsMemoryOverrun(int location, int value)
+{
+ int i, offset;
+ int index;
+ void *addr;
+
+ i = 0;
+ offset = 0;
+
+ // Search down the array until we find the right entry
+
+ while (intercepts_overrun[i].len != 0)
+ {
+ if (offset + intercepts_overrun[i].len > location)
+ {
+ addr = intercepts_overrun[i].addr;
+
+ // Write the value to the memory location.
+ // 16-bit and 32-bit values are written differently.
+
+ if (addr != NULL)
+ {
+ if (intercepts_overrun[i].int16_array)
+ {
+ index = (location - offset) / 2;
+ ((short *) addr)[index] = value & 0xffff;
+ ((short *) addr)[index + 1] = (value >> 16) & 0xffff;
+ }
+ else
+ {
+ index = (location - offset) / 4;
+ ((int *) addr)[index] = value;
+ }
+ }
+
+ break;
+ }
+
+ offset += intercepts_overrun[i].len;
+ ++i;
+ }
+}
+
+// Emulate overruns of the intercepts[] array.
+
+static void InterceptsOverrun(int num_intercepts, intercept_t *intercept)
+{
+ int location;
+
+ if (num_intercepts <= MAXINTERCEPTS_ORIGINAL)
+ {
+ // No overrun
+
+ return;
+ }
+
+ location = (num_intercepts - MAXINTERCEPTS_ORIGINAL - 1) * 12;
+
+ // Overwrite memory that is overwritten in Vanilla Doom, using
+ // the values from the intercept structure.
+ //
+ // Note: the ->d.{thing,line} member should really have its
+ // address translated into the correct address value for
+ // Vanilla Doom.
+
+ InterceptsMemoryOverrun(location, intercept->frac);
+ InterceptsMemoryOverrun(location + 4, intercept->isaline);
+ InterceptsMemoryOverrun(location + 8, (int) intercept->d.thing);
+}
+
+
+//
+// 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.
+//
+// [STRIFE] Verified unmodified
+//
+boolean
+P_PathTraverse
+( fixed_t x1,
+ fixed_t y1,
+ fixed_t x2,
+ fixed_t y2,
+ int flags,
+ boolean (*trav) (intercept_t *))
+{
+ fixed_t xt1;
+ fixed_t yt1;
+ fixed_t xt2;
+ fixed_t yt2;
+
+ fixed_t xstep;
+ fixed_t ystep;
+
+ fixed_t partial;
+
+ fixed_t xintercept;
+ fixed_t yintercept;
+
+ int mapx;
+ int mapy;
+
+ int mapxstep;
+ int mapystep;
+
+ int count;
+
+ earlyout = flags & PT_EARLYOUT;
+
+ validcount++;
+ intercept_p = intercepts;
+
+ if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
+ x1 += FRACUNIT; // don't side exactly on a line
+
+ if ( ((y1-bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
+ 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,abs(x2-x1));
+ }
+ else if (xt2 < xt1)
+ {
+ mapxstep = -1;
+ partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
+ ystep = FixedDiv (y2-y1,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,abs(y2-y1));
+ }
+ else if (yt2 < yt1)
+ {
+ mapystep = -1;
+ partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
+ xstep = FixedDiv (x2-x1,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/src/strife/p_mobj.c b/src/strife/p_mobj.c
new file mode 100644
index 00000000..53d12f9c
--- /dev/null
+++ b/src/strife/p_mobj.c
@@ -0,0 +1,1352 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+
+#include "i_system.h"
+#include "z_zone.h"
+#include "m_random.h"
+#include "doomdef.h"
+#include "p_local.h"
+#include "sounds.h"
+#include "st_stuff.h"
+#include "hu_stuff.h"
+#include "s_sound.h"
+#include "doomstat.h"
+#include "d_main.h" // villsa [STRIFE]
+
+extern line_t *spechit[]; // haleyjd:
+extern int numspechit; // [STRIFE] - needed in P_XYMovement
+
+
+void G_PlayerReborn (int player);
+void P_SpawnMapThing (mapthing_t* mthing);
+
+
+//
+// P_SetMobjState
+// Returns true if the mobj is still present.
+//
+// [STRIFE] Verified unmodified
+//
+int test;
+
+boolean
+P_SetMobjState
+( mobj_t* mobj,
+ statenum_t state )
+{
+ state_t* st;
+
+ do
+ {
+ if (state == S_NULL)
+ {
+ mobj->state = (state_t *) S_NULL;
+ P_RemoveMobj (mobj);
+ return false;
+ }
+
+ 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.acp1)
+ st->action.acp1(mobj);
+
+ state = st->nextstate;
+ } while (!mobj->tics);
+
+ return true;
+}
+
+
+//
+// P_ExplodeMissile
+//
+// [STRIFE] Removed randomization of deathstate tics
+//
+void P_ExplodeMissile (mobj_t* mo)
+{
+ mo->momx = mo->momy = mo->momz = 0;
+
+ P_SetMobjState (mo, mobjinfo[mo->type].deathstate);
+
+ // villsa [STRIFE] removed tics randomization
+
+ mo->flags &= ~MF_MISSILE;
+
+ if (mo->info->deathsound)
+ S_StartSound (mo, mo->info->deathsound);
+}
+
+
+//
+// P_XYMovement
+//
+// [STRIFE] Modifications for:
+// * No SKULLFLY logic (replaced by BOUNCE flag)
+// * Missiles can activate G1/GR line types
+// * Player walking logic
+// * Air friction for players
+//
+#define STOPSPEED 0x1000
+#define FRICTION 0xe800
+#define AIRFRICTION 0xfff0 // [STRIFE]
+
+void P_XYMovement (mobj_t* mo)
+{
+ fixed_t ptryx;
+ fixed_t ptryy;
+ player_t* player;
+ fixed_t xmove;
+ fixed_t ymove;
+
+ // villsa [STRIFE] unused
+ /*
+ if (!mo->momx && !mo->momy)
+ {
+ if (mo->flags & MF_SKULLFLY)
+ {
+ // the skull slammed into something
+ mo->flags &= ~MF_SKULLFLY;
+ mo->momx = mo->momy = 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;
+
+ do
+ {
+ if (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;
+ }
+
+ if (!P_TryMove (mo, ptryx, ptryy))
+ {
+ // blocked move
+ if (mo->player)
+ { // try to slide along it
+ P_SlideMove (mo);
+ }
+ // villsa [STRIFE] check for bouncy missiles
+ else if(mo->flags & MF_BOUNCE)
+ {
+ mo->momx >>= 3;
+ mo->momy >>= 3;
+
+ if (P_TryMove(mo, mo->x - xmove, ymove + mo->y))
+ mo->momy = -mo->momy;
+ else
+ mo->momx = -mo->momx;
+
+ xmove = 0;
+ ymove = 0;
+ }
+ else if (mo->flags & MF_MISSILE)
+ {
+ // haley 20110203: [STRIFE]
+ // This modification allows missiles to activate shoot specials.
+ // *** BUG: In vanilla Strife the second condition is simply
+ // if(numspechit). However, numspechit can be negative, and
+ // when it is, this accesses spechit[-2]. This always causes the
+ // DOS exe to read from NULL, and the 'special' value there (in
+ // DOS 6.22 at least) is 0x70, which does nothing.
+ if(blockingline && blockingline->special)
+ P_ShootSpecialLine(mo, blockingline);
+ if(numspechit > 0)
+ P_ShootSpecialLine(mo, spechit[numspechit-1]);
+
+ // explode a missile
+ if (ceilingline &&
+ ceilingline->backsector &&
+ ceilingline->backsector->ceilingpic == skyflatnum)
+ {
+ // Hack to prevent missiles exploding
+ // against the sky.
+ // Does not handle sky floors.
+ P_RemoveMobj (mo);
+ return;
+ }
+ P_ExplodeMissile (mo);
+ }
+ else
+ mo->momx = mo->momy = 0;
+ }
+ } while (xmove || ymove);
+
+ // slow down
+ if (player && player->cheats & CF_NOMOMENTUM)
+ {
+ // debug option for no sliding at all
+ mo->momx = mo->momy = 0;
+ return;
+ }
+
+ // villsa [STRIFE] replace skullfly flag with MF_BOUNCE
+ if (mo->flags & (MF_MISSILE | MF_BOUNCE) )
+ return; // no friction for missiles ever
+
+ // haleyjd 20110224: [STRIFE] players experience friction even in the air,
+ // although less than when on the ground. With this fix, the 1.2-and-up
+ // IWAD demo is now in sync!
+ if (mo->z > mo->floorz)
+ {
+ if(player)
+ {
+ mo->momx = FixedMul (mo->momx, AIRFRICTION);
+ mo->momy = FixedMul (mo->momy, AIRFRICTION);
+ }
+ return; // no friction when airborne
+ }
+
+ if (mo->flags & MF_CORPSE)
+ {
+ // do not stop sliding
+ // if halfway off a step with some momentum
+ if (mo->momx > FRACUNIT/4
+ || mo->momx < -FRACUNIT/4
+ || mo->momy > FRACUNIT/4
+ || mo->momy < -FRACUNIT/4)
+ {
+ if (mo->floorz != mo->subsector->sector->floorheight)
+ return;
+ }
+ }
+
+ if (mo->momx > -STOPSPEED
+ && mo->momx < STOPSPEED
+ && mo->momy > -STOPSPEED
+ && mo->momy < STOPSPEED
+ && (!player
+ || (player->cmd.forwardmove == 0
+ && player->cmd.sidemove == 0 ) ) )
+ {
+ // if in a walking frame, stop moving
+ // villsa [STRIFE]: different player state (haleyjd - verified 20110202)
+ if ( player&&(unsigned)((player->mo->state - states) - S_PLAY_01) < 4)
+ P_SetMobjState (player->mo, S_PLAY_00);
+
+ mo->momx = 0;
+ mo->momy = 0;
+ }
+ else
+ {
+ mo->momx = FixedMul (mo->momx, FRICTION);
+ mo->momy = FixedMul (mo->momy, FRICTION);
+ }
+}
+
+//
+// P_ZMovement
+//
+// [STRIFE] Modifications for:
+// * 3D Object Clipping
+// * Different momz handling
+// * No SKULLFLY logic (replaced with BOUNCE)
+// * Missiles don't hit sky flats
+//
+void P_ZMovement (mobj_t* mo)
+{
+ fixed_t dist;
+ fixed_t delta;
+
+ // check for smooth step up
+ if (mo->player && mo->z < mo->floorz)
+ {
+ mo->player->viewheight -= mo->floorz-mo->z;
+
+ mo->player->deltaviewheight
+ = (VIEWHEIGHT - mo->player->viewheight)>>3;
+ }
+
+ // adjust height
+ // villsa [STRIFE] check for things standing on top of other things
+ if(!P_CheckPositionZ(mo, mo->z + mo->momz))
+ {
+ if(mo->momz >= 0)
+ mo->ceilingz = mo->height + mo->z;
+ else
+ mo->floorz = mo->z;
+ }
+
+ //mo->z += mo->momz; // villsa [STRIFE] unused
+
+ if ( mo->flags & MF_FLOAT
+ && mo->target)
+ {
+ // float down towards target if too close
+ if ( /*!(mo->flags & MF_SKULLFLY) // villsa [STRIFE] unused
+ &&*/ !(mo->flags & MF_INFLOAT) )
+ {
+ dist = P_AproxDistance (mo->x - mo->target->x,
+ mo->y - mo->target->y);
+
+ delta =(mo->target->z + (mo->height>>1)) - mo->z;
+
+ if (delta<0 && dist < -(delta*3) )
+ mo->z -= FLOATSPEED;
+ else if (delta>0 && dist < (delta*3) )
+ mo->z += FLOATSPEED;
+ }
+ }
+
+ // clip movement
+ if (mo->z <= mo->floorz)
+ {
+ // hit the floor
+
+ if (mo->flags & MF_BOUNCE)
+ {
+ // the skull slammed into something
+ // villsa [STRIFE] affect reactiontime
+ // momz is also shifted by 1
+ mo->momz = -mo->momz >> 1;
+ mo->reactiontime >>= 1;
+
+ // villsa [STRIFE] get terrain type
+ if(P_GetTerrainType(mo) != FLOOR_SOLID)
+ mo->flags &= ~MF_BOUNCE;
+ }
+
+ if (mo->momz < 0)
+ {
+ if (mo->player
+ && 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;
+
+ // villsa [STRIFE] fall damage
+ // haleyjd 09/18/10: Repaired calculation
+ if(mo->momz < -20*FRACUNIT)
+ P_DamageMobj(mo, NULL, mo, mo->momz / -25000);
+
+ // haleyjd 20110224: *Any* fall centers your view, not just
+ // damaging falls (moved outside the above if).
+ mo->player->centerview = 1;
+ 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.
+ //
+
+ // villsa [STRIFE] unused
+ /*
+ if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY)
+ mo->momz = -mo->momz;
+ */
+
+ // villsa [STRIFE] also check for MF_BOUNCE
+ if ( (mo->flags & MF_MISSILE)
+ && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) )
+ {
+ P_ExplodeMissile (mo);
+ }
+ }
+ else // haleyjd 20110224: else here, not else if - Strife change or what?
+ {
+ if (! (mo->flags & MF_NOGRAVITY) )
+ {
+ if (mo->momz == 0)
+ mo->momz = -GRAVITY*2;
+ else
+ mo->momz -= GRAVITY;
+ }
+
+ if (mo->z + mo->height > mo->ceilingz)
+ {
+ // villsa [STRIFE] replace skullfly flag with MF_BOUNCE
+ if (mo->flags & MF_BOUNCE)
+ {
+ // villsa [STRIFE] affect reactiontime
+ // momz is also shifted by 1
+ mo->momz = -mo->momz >> 1;
+ mo->reactiontime >>= 1;
+ }
+
+ // hit the ceiling
+ if (mo->momz > 0)
+ mo->momz = 0;
+
+ mo->z = mo->ceilingz - mo->height;
+
+ // villsa [STRIFE] also check for MF_BOUNCE
+ if ( (mo->flags & MF_MISSILE)
+ && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) )
+ {
+ // villsa [STRIFE] check against skies
+ if(mo->subsector->sector->ceilingpic == skyflatnum)
+ P_RemoveMobj(mo);
+ else
+ P_ExplodeMissile (mo);
+ }
+ }
+ }
+}
+
+
+
+//
+// P_NightmareRespawn
+//
+// [STRIFE] Modifications for:
+// * Destination fog z coordinate
+// * Restoration of all Strife mapthing flags
+//
+void
+P_NightmareRespawn (mobj_t* mobj)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobj_t* mo;
+ mapthing_t* mthing;
+
+ x = mobj->spawnpoint.x << FRACBITS;
+ y = mobj->spawnpoint.y << FRACBITS;
+
+ // somthing is occupying it's 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);
+
+ // haleyjd [STRIFE]: Uses ONFLOORZ instead of ss->sector->floorheight
+ mo = P_SpawnMobj (x, y, ONFLOORZ , MT_TFOG);
+
+ S_StartSound (mo, sfx_telept);
+
+ // spawn the new monster
+ mthing = &mobj->spawnpoint;
+
+ // spawn it
+ 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;
+ if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs
+ mobj->flags |= MF_STAND;
+ if (mthing->options & MTF_FRIEND) // [STRIFE] Allies
+ mobj->flags |= MF_ALLY;
+ if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object
+ mobj->flags |= MF_SHADOW;
+ if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency
+ mobj->flags |= MF_MVIS;
+
+ mo->reactiontime = 18;
+
+ // remove the old monster,
+ P_RemoveMobj (mobj);
+}
+
+
+//
+// P_MobjThinker
+//
+// [STRIFE] Modified for:
+// * Terrain effects
+// * Stonecold cheat
+// * Altered skill 5 respawn behavior
+//
+void P_MobjThinker (mobj_t* mobj)
+{
+ // momentum movement
+ if (mobj->momx
+ || mobj->momy
+ /*|| (mobj->flags&MF_SKULLFLY)*/ ) // villsa [STRIFE] unused
+ {
+ P_XYMovement (mobj);
+
+ // FIXME: decent NOP/NULL/Nil function pointer please.
+ if (mobj->thinker.function.acv == (actionf_v) (-1))
+ return; // mobj was removed
+
+ // villsa [STRIFE] terrain clipping
+ if(P_GetTerrainType(mobj) == FLOOR_SOLID)
+ mobj->flags &= ~MF_FEETCLIPPED;
+ else
+ mobj->flags |= MF_FEETCLIPPED;
+
+ }
+ if ( (mobj->z != mobj->floorz && !(mobj->flags & MF_NOGRAVITY)) // villsa [STRIFE]
+ || mobj->momz )
+ {
+ P_ZMovement (mobj);
+
+ // FIXME: decent NOP/NULL/Nil function pointer please.
+ if (mobj->thinker.function.acv == (actionf_v) (-1))
+ return; // mobj was removed
+
+ // villsa [STRIFE] terrain clipping and sounds
+ if(P_GetTerrainType(mobj) == FLOOR_SOLID)
+ mobj->flags &= ~MF_FEETCLIPPED;
+ else
+ {
+ S_StartSound(mobj, sfx_wsplsh);
+ mobj->flags |= MF_FEETCLIPPED;
+ }
+
+ }
+
+
+ // cycle through states,
+ // calling action functions at transitions
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+
+ // villsa [STRIFE] stonecold cheat
+ if(stonecold)
+ {
+ if(mobj->flags & MF_COUNTKILL)
+ P_DamageMobj(mobj, mobj, mobj, 10);
+ }
+
+ // 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++;
+
+ // haleyjd [STRIFE]: respawn time increased from 12 to 16
+ if (mobj->movecount < 16*TICRATE)
+ return;
+
+ if ( leveltime&31 )
+ return;
+
+ if (P_Random () > 4)
+ return;
+
+ // haleyjd [STRIFE]: NOTDMATCH things don't respawn
+ if(mobj->flags & MF_NOTDMATCH)
+ return;
+
+ P_NightmareRespawn (mobj);
+ }
+}
+
+
+//
+// P_SpawnMobj
+//
+// [STRIFE] Modifications to reactiontime and for terrain types.
+//
+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;
+ mobj->flags = info->flags;
+ mobj->health = info->spawnhealth;
+
+ // haleyjd 09/25/10: [STRIFE] Doesn't do this; messes up flamethrower
+ // and a lot of other stuff using reactiontime as a counter.
+ //if (gameskill != sk_nightmare)
+ mobj->reactiontime = info->reactiontime;
+
+ mobj->lastlook = P_Random () % 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;
+
+ // set subsector and/or block links
+ P_SetThingPosition (mobj);
+
+ mobj->floorz = mobj->subsector->sector->floorheight;
+ mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+
+ if (z == ONFLOORZ)
+ {
+ mobj->z = mobj->floorz;
+
+ // villsa [STRIFE]
+ if(P_GetTerrainType(mobj) != FLOOR_SOLID)
+ mobj->flags |= MF_FEETCLIPPED;
+
+ }
+ else if (z == ONCEILINGZ)
+ mobj->z = mobj->ceilingz - mobj->info->height;
+ else
+ mobj->z = z;
+
+ mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
+
+ P_AddThinker (&mobj->thinker);
+
+ return mobj;
+}
+
+
+//
+// P_RemoveMobj
+//
+// [STRIFE] Modifications for item respawn timing
+//
+mapthing_t itemrespawnque[ITEMQUESIZE];
+int itemrespawntime[ITEMQUESIZE];
+int iquehead;
+int iquetail;
+
+void P_RemoveMobj (mobj_t* mobj)
+{
+ // villsa [STRIFE] removed invuln/invis. sphere exceptions
+ if ((mobj->flags & MF_SPECIAL)
+ && !(mobj->flags & MF_DROPPED))
+ {
+ itemrespawnque[iquehead] = mobj->spawnpoint;
+ itemrespawntime[iquehead] = leveltime + 30*TICRATE; // [STRIFE]
+ iquehead = (iquehead+1)&(ITEMQUESIZE-1);
+
+ // [STRIFE] FIXME/TODO: - haleyjd 20110629
+ // -random parameter affects the behavior of respawning items here.
+ // However, this requires addition of randomparm to the transmission
+ // of variables during netgame initialization, and the netcode is not
+ // functional yet - so, I haven't added this yet!
+
+ // lose one off the end?
+ if (iquehead == iquetail)
+ iquetail = (iquetail+1)&(ITEMQUESIZE-1);
+ }
+
+ // unlink from sector and block lists
+ P_UnsetThingPosition (mobj);
+
+ // stop any playing sound
+ S_StopSound (mobj);
+
+ // free block
+ P_RemoveThinker ((thinker_t*)mobj);
+}
+
+
+
+
+//
+// P_RespawnSpecials
+//
+// [STRIFE] modification to item respawn time handling
+//
+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;
+
+ // haleyjd [STRIFE]: 30 second wait is not accounted for here, see above.
+ if (leveltime < itemrespawntime[iquetail])
+ 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
+ for (i=0 ; i< NUMMOBJTYPES ; i++)
+ {
+ if (mthing->type == mobjinfo[i].doomednum)
+ break;
+ }
+
+ // 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 que
+ 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.
+//
+// [STRIFE] Modifications for:
+// * stonecold cheat, -workparm
+// * default inventory/questflags
+//
+void P_SpawnPlayer(mapthing_t* mthing)
+{
+ player_t* p;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobj_t* mobj;
+
+ if(mthing->type == 0)
+ return;
+
+ // 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 > 1)
+ mobj->flags |= (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;
+
+ // setup gun psprite
+ P_SetupPsprites(p);
+
+ // villsa [STRIFE]
+ stonecold = false;
+
+ // villsa [STRIFE] what a nasty hack...
+ if(gamemap == 10)
+ p->weaponowned[wp_sigil] = true;
+
+ // villsa [STRIFE] instead of just giving cards in deathmatch mode, also
+ // set accuracy to 50 and give all quest flags
+ if(deathmatch)
+ {
+ int i;
+
+ p->accuracy = 50;
+ p->questflags = QF_ALLQUESTS; // 0x7fffffff
+
+ for(i = 0; i < NUMCARDS; i++)
+ p->cards[i] = true;
+ }
+
+ // villsa [STRIFE] set godmode?
+ if(workparm)
+ p->cheats |= CF_GODMODE;
+
+ if(mthing->type - 1 == consoleplayer)
+ {
+ // wake up the status bar
+ ST_Start ();
+ // wake up the heads up text
+ HU_Start ();
+ }
+}
+
+
+//
+// P_SpawnMapThing
+// The fields of the mapthing should
+// already be in host byte order.
+//
+// [STRIFE] Modifications for:
+// * No Lost Souls, item count
+// * New mapthing_t flag bits
+// * 8-player support
+//
+void P_SpawnMapThing (mapthing_t* mthing)
+{
+ int i;
+ int bit;
+ mobj_t* mobj;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+
+ // count deathmatch start positions
+ if (mthing->type == 11)
+ {
+ if (deathmatch_p < &deathmatchstarts[10])
+ {
+ memcpy (deathmatch_p, mthing, sizeof(*mthing));
+ deathmatch_p++;
+ }
+ return;
+ }
+
+ if (mthing->type <= 0)
+ {
+ // Thing type 0 is actually "player -1 start".
+ // For some reason, Vanilla Doom accepts/ignores this.
+
+ return;
+ }
+
+ // check for players specially
+ // haleyjd 20120209: [STRIFE] 8 player starts
+ if (mthing->type <= 8)
+ {
+ // save spots for respawning in network games
+ playerstarts[mthing->type-1] = *mthing;
+ if (!deathmatch)
+ P_SpawnPlayer (mthing);
+
+ return;
+ }
+
+ // check for apropriate skill level
+ if (!netgame && (mthing->options & 16) )
+ return;
+
+ if (gameskill == sk_baby)
+ bit = 1;
+ else if (gameskill == sk_nightmare)
+ bit = 4;
+ else
+ bit = 1<<(gameskill-1);
+
+ if (!(mthing->options & bit) )
+ return;
+
+ // find which type to spawn
+ for (i=0 ; i< NUMMOBJTYPES ; i++)
+ if (mthing->type == mobjinfo[i].doomednum)
+ break;
+
+ if (i==NUMMOBJTYPES)
+ I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)",
+ mthing->type,
+ mthing->x, mthing->y);
+
+ // don't spawn keycards and players in deathmatch
+ if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
+ return;
+
+ // don't spawn any monsters if -nomonsters
+ // villsa [STRIFE] Removed MT_SKULL
+ if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL))
+ return;
+
+ // spawn it
+ 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 () % mobj->tics);
+ if (mobj->flags & MF_COUNTKILL)
+ totalkills++;
+
+ // villsa [STRIFE] unused
+ /*
+ if (mobj->flags & MF_COUNTITEM)
+ totalitems++;
+ */
+
+ mobj->angle = ANG45 * (mthing->angle/45);
+ if (mthing->options & MTF_AMBUSH)
+ mobj->flags |= MF_AMBUSH;
+ if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs
+ mobj->flags |= MF_STAND;
+ if (mthing->options & MTF_FRIEND) // [STRIFE] Allies
+ mobj->flags |= MF_ALLY;
+ if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object
+ mobj->flags |= MF_SHADOW;
+ if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency
+ mobj->flags |= MF_MVIS;
+}
+
+
+
+//
+// GAME SPAWN FUNCTIONS
+//
+
+
+//
+// P_SpawnPuff
+//
+// [STRIFE] Modifications for:
+// * No spawn tics randomization
+// * Player melee behavior
+//
+extern fixed_t attackrange;
+
+void
+P_SpawnPuff
+( fixed_t x,
+ fixed_t y,
+ fixed_t z )
+{
+ mobj_t* th;
+ int t;
+
+ t = P_Random();
+ z += ((t - P_Random()) << 10);
+
+ // [STRIFE] removed momz and tics randomization
+
+ th = P_SpawnMobj(x, y, z, MT_STRIFEPUFF); // [STRIFE]: new type
+
+ // don't make punches spark on the wall
+ // [STRIFE] Use a separate melee attack range for the player
+ if(attackrange == PLAYERMELEERANGE)
+ P_SetMobjState(th, S_POW2_00); // 141
+
+ // villsa [STRIFE] unused
+ /*
+ if (th->tics < 1)
+ th->tics = 1;
+ */
+}
+
+//
+// P_SpawnSparkPuff
+//
+// villsa [STRIFE] new function
+//
+mobj_t* P_SpawnSparkPuff(fixed_t x, fixed_t y, fixed_t z)
+{
+ int t = P_Random();
+ return P_SpawnMobj(x, y, ((t - P_Random()) << 10) + z, MT_SPARKPUFF);
+}
+
+//
+// P_SpawnBlood
+//
+// [STRIFE] Modifications for:
+// * No spawn tics randomization
+// * Different damage ranges for state setting
+//
+void
+P_SpawnBlood
+( fixed_t x,
+ fixed_t y,
+ fixed_t z,
+ int damage )
+{
+ mobj_t* th;
+ int temp;
+
+ temp = P_Random();
+ z += (temp - P_Random()) << 10;
+ th = P_SpawnMobj(x, y, z, MT_BLOOD_DEATH);
+ th->momz = FRACUNIT*2;
+
+ // villsa [STRIFE]: removed tics randomization
+
+ // villsa [STRIFE] different checks for damage range
+ if(damage >= 10 && damage <= 13)
+ P_SetMobjState(th, S_BLOD_00);
+ else if(damage >= 7 && damage < 10)
+ P_SetMobjState(th, S_BLOD_01);
+ else if(damage < 7)
+ P_SetMobjState(th, S_BLOD_02);
+}
+
+
+
+//
+// P_CheckMissileSpawn
+// Moves the missile forward a bit
+// and possibly explodes it right there.
+//
+// [STRIFE] Modifications for:
+// * No spawn tics randomization
+//
+void P_CheckMissileSpawn (mobj_t* th)
+{
+ // villsa [STRIFE] removed tics randomization
+
+ // 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);
+
+ if (!P_TryMove (th, th->x, th->y))
+ P_ExplodeMissile (th);
+}
+
+// Certain functions assume that a mobj_t pointer is non-NULL,
+// causing a crash in some situations where it is NULL. Vanilla
+// Doom did not crash because of the lack of proper memory
+// protection. This function substitutes NULL pointers for
+// pointers to a dummy mobj, to avoid a crash.
+
+mobj_t *P_SubstNullMobj(mobj_t *mobj)
+{
+ if (mobj == NULL)
+ {
+ static mobj_t dummy_mobj;
+
+ dummy_mobj.x = 0;
+ dummy_mobj.y = 0;
+ dummy_mobj.z = 0;
+ dummy_mobj.flags = 0;
+
+ mobj = &dummy_mobj;
+ }
+
+ return mobj;
+}
+
+//
+// P_SpawnMissile
+//
+// [STRIFE] Added MVIS inaccuracy
+//
+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);
+
+ 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)
+ {
+ int t = P_Random(); // haleyjd 20110223: remove order-of-evaluation dependencies
+ an += (t - P_Random()) << 21;
+ }
+ // villsa [STRIFE] check for heavily transparent things
+ else if(dest->flags & MF_MVIS)
+ {
+ int t = P_Random();
+ an += (t - P_Random()) << 22;
+ }
+
+ 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_SpawnFacingMissile
+//
+// villsa [STRIFE] new function
+// Spawn a missile based on source's angle
+//
+mobj_t* P_SpawnFacingMissile(mobj_t* source, mobj_t* target, mobjtype_t type)
+{
+ mobj_t* th;
+ angle_t an;
+ fixed_t dist;
+
+ th = P_SpawnMobj(source->x, source->y, source->z + (32*FRACUNIT), type);
+
+ if(th->info->seesound)
+ S_StartSound(th, th->info->seesound);
+
+ th->target = source; // where it came from
+ th->angle = source->angle; // haleyjd 09/06/10: fix0red
+ an = th->angle;
+
+ // fuzzy player
+ if (target->flags & MF_SHADOW)
+ {
+ int t = P_Random();
+ an += (t - P_Random()) << 21;
+ }
+ // villsa [STRIFE] check for heavily transparent things
+ else if(target->flags & MF_MVIS)
+ {
+ int t = P_Random();
+ an += (t - P_Random()) << 22;
+ }
+
+ an >>= ANGLETOFINESHIFT;
+ th->momx = FixedMul (th->info->speed, finecosine[an]);
+ th->momy = FixedMul (th->info->speed, finesine[an]);
+
+ dist = P_AproxDistance (target->x - source->x, target->y - source->y);
+ dist = dist / th->info->speed;
+
+ if(dist < 1)
+ dist = 1;
+
+ th->momz = (target->z - source->z) / dist;
+ P_CheckMissileSpawn (th);
+
+ return th;
+}
+
+//
+// P_SpawnPlayerMissile
+//
+// Tries to aim at a nearby monster
+// villsa [STRIFE] now returns a mobj
+// * Also modified to allow up/down look, and to account for foot-clipping
+// by liquid terrain.
+//
+mobj_t* P_SpawnPlayerMissile(mobj_t* source, mobjtype_t type)
+{
+ mobj_t* th;
+ angle_t an;
+
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ fixed_t slope;
+
+ // see which target is to be aimed at
+ an = source->angle;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+
+ if (!linetarget)
+ {
+ an += 1<<26;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+
+ if (!linetarget)
+ {
+ an -= 2<<26;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+ }
+
+ if (!linetarget)
+ {
+ an = source->angle;
+
+ // haleyjd 09/21/10: [STRIFE] Removed, for look up/down support.
+ //slope = 0;
+ }
+ }
+
+ // villsa [STRIFE]
+ if(linetarget)
+ source->target = linetarget;
+
+ x = source->x;
+ y = source->y;
+
+ // villsa [STRIFE]
+ if(!(source->flags & MF_FEETCLIPPED))
+ z = source->z + 32*FRACUNIT;
+ else
+ z = source->z + 22*FRACUNIT;
+
+ th = P_SpawnMobj (x,y,z, type);
+
+ if (th->info->seesound)
+ S_StartSound (th, th->info->seesound);
+
+ 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);
+
+ return th;
+}
+
+//
+// P_SpawnMortar
+//
+// villsa [STRIFE] new function
+// Spawn a high-arcing ballistic projectile
+//
+mobj_t* P_SpawnMortar(mobj_t *source, mobjtype_t type)
+{
+ mobj_t* th;
+ angle_t an;
+ fixed_t slope;
+
+ an = source->angle;
+
+ th = P_SpawnMobj(source->x, source->y, source->z, type);
+ th->target = source;
+ th->angle = an;
+ an >>= ANGLETOFINESHIFT;
+
+ // haleyjd 20110203: corrected order of function calls
+ th->momx = FixedMul(th->info->speed, finecosine[an]);
+ th->momy = FixedMul(th->info->speed, finesine[an]);
+
+ P_CheckMissileSpawn(th);
+
+ slope = P_AimLineAttack(source, source->angle, 1024*FRACUNIT);
+ th->momz = FixedMul(th->info->speed, slope);
+
+ return th;
+}
diff --git a/src/strife/p_mobj.h b/src/strife/p_mobj.h
new file mode 100644
index 00000000..0e482311
--- /dev/null
+++ b/src/strife/p_mobj.h
@@ -0,0 +1,338 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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
+//
+typedef enum
+{
+ // Call P_SpecialThing when touched.
+ MF_SPECIAL = 1,
+
+ // Blocks.
+ MF_SOLID = 2,
+
+ // Can be hit.
+ MF_SHOOTABLE = 4,
+
+ // Don't use the sector links (invisible but touchable).
+ MF_NOSECTOR = 8,
+
+ // Don't use the blocklinks (inert but displayable)
+ MF_NOBLOCKMAP = 16,
+
+ // villsa [STRIFE] Stand around until alerted
+ MF_STAND = 32,
+
+ // Will try to attack right back.
+ MF_JUSTHIT = 64,
+
+ // Will take at least one step before attacking.
+ MF_JUSTATTACKED = 128,
+
+ // On level spawning (initial position),
+ // hang from ceiling instead of stand on floor.
+ MF_SPAWNCEILING = 256,
+
+ // Don't apply gravity (every tic),
+ // that is, object will float, keeping current height
+ // or changing it actively.
+ MF_NOGRAVITY = 512,
+
+ // Movement flags.
+ // This allows jumps from high places.
+ MF_DROPOFF = 0x400,
+
+ // villsa [STRIFE] For players, count as quest item
+ MF_GIVEQUEST = 0x800,
+
+ // Player cheat. ???
+ MF_NOCLIP = 0x1000,
+
+ // villsa [STRIFE] are feet clipped into water/slude floor?
+ MF_FEETCLIPPED = 0x2000,
+
+ // Allow moves to any height, no gravity.
+ // For active floaters, e.g. cacodemons, pain elementals.
+ MF_FLOAT = 0x4000,
+
+ // villsa [STRIFE] can NPC talk?
+ MF_NODIALOG = 0x8000,
+
+ // Don't hit same species, explode on block.
+ // Player missiles as well as fireballs of various kinds.
+ MF_MISSILE = 0x10000,
+
+ // Dropped by a demon, not level spawned.
+ // E.g. ammo clips dropped by dying former humans.
+ MF_DROPPED = 0x20000,
+
+ // Use fuzzy draw (shadow demons or spectres),
+ // temporary player invisibility powerup.
+ MF_SHADOW = 0x40000,
+
+ // Flag: don't bleed when shot (use puff),
+ // barrels and shootable furniture shall not bleed.
+ MF_NOBLOOD = 0x80000,
+
+ // Don't stop moving halfway off a step,
+ // that is, have dead bodies slide down all the way.
+ MF_CORPSE = 0x100000,
+
+ // Floating to a height for a move, ???
+ // don't auto float to target's height.
+ MF_INFLOAT = 0x200000,
+
+ // On kill, count this enemy object
+ // towards intermission kill total.
+ // Happy gathering.
+ MF_COUNTKILL = 0x400000,
+
+ // Not to be activated by sound, deaf monster.
+ MF_AMBUSH = 0x800000,
+
+ // villsa [STRIFE] flag used for bouncing projectiles
+ MF_BOUNCE = 0x1000000,
+
+ // Don't spawn this object
+ // in death match mode (e.g. key cards).
+ MF_NOTDMATCH = 0x2000000,
+
+ // villsa [STRIFE] friendly towards player with matching flag
+ MF_ALLY = 0x4000000,
+
+ // villsa [STRIFE] 75% or 25% transparency? -- NEEDS VERIFICATION
+ MF_MVIS = 0x8000000,
+
+ // villsa [STRIFE] color translation
+ MF_COLORSWAP1 = 0x10000000,
+
+ // villsa [STRIFE] color translation
+ MF_COLORSWAP2 = 0x20000000,
+
+ // villsa [STRIFE] color translation
+ MF_COLORSWAP3 = 0x40000000,
+
+ // villsa [STRIFE] spectral entity, only damaged by spectral missiles
+ MF_SPECTRAL = 0x80000000,
+
+ // Player sprites in multiplayer modes are modified
+ // using an internal color lookup table for re-indexing.
+ // haleyjd 09/06/10: redid for Strife translations
+ MF_TRANSLATION = (MF_COLORSWAP1|MF_COLORSWAP2|MF_COLORSWAP3),
+
+ // Turns 0x10000000 into 0x01 to get a translation index.
+ // villsa [STRIFE] change from 26 to 28
+ MF_TRANSSHIFT = 28
+
+} mobjflag_t;
+
+
+// Map Object definition.
+//
+// [STRIFE]: Amazingly, only one modification was made to mobj_t over DOOM
+// 1.666, and that was the addition of the single-byte allegiance field for
+// tracking with which player friendly monsters are allied.
+//
+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;
+
+ //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;
+
+ struct subsector_s* subsector;
+
+ // The closest interval over all contacted Sectors.
+ fixed_t floorz;
+ fixed_t ceilingz;
+
+ // 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;
+ int flags;
+ int health;
+
+ // Movement direction, movement generation (zig-zagging).
+ int movedir; // 0-7
+ int movecount; // when 0, select a new dir
+
+ // 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.
+ int reactiontime;
+
+ // If >0, the target will be chased
+ // no matter what (even if shot)
+ int threshold;
+
+ // Additional info record for player avatars only.
+ // Only valid if type == MT_PLAYER
+ struct player_s* player;
+
+ // Player number last looked for.
+ int lastlook;
+
+ // For nightmare respawn.
+ mapthing_t spawnpoint;
+
+ // Thing being chased/attacked for tracers.
+ struct mobj_s* tracer;
+
+ // [STRIFE] haleyjd 09/05/10:
+ // * In multiplayer this stores allegiance, for friends and teleport beacons
+ // * In single-player this tracks dialog state.
+ byte miscdata;
+
+} mobj_t;
+
+// haleyjd [STRIFE] Exported
+void P_CheckMissileSpawn (mobj_t* th);
+
+#endif
diff --git a/src/strife/p_plats.c b/src/strife/p_plats.c
new file mode 100644
index 00000000..51424760
--- /dev/null
+++ b/src/strife/p_plats.c
@@ -0,0 +1,362 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+
+#include "i_system.h"
+#include "z_zone.h"
+#include "m_random.h"
+
+#include "doomdef.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+// Data.
+#include "sounds.h"
+
+
+plat_t* activeplats[MAXPLATS];
+
+
+
+//
+// Move a plat up and down
+//
+void T_PlatRaise(plat_t* plat)
+{
+ result_e res;
+
+ switch(plat->status)
+ {
+ case up:
+ res = T_MovePlane(plat->sector, plat->speed, plat->high, plat->crush, 0, 1);
+
+ if(plat->type == raiseAndChange
+ || plat->type == raiseToNearestAndChange)
+ {
+ if(!(leveltime&7))
+ S_StartSound(&plat->sector->soundorg, sfx_stnmov);
+ }
+
+ // villsa [STRIFE]
+ if(plat->type == slowDWUS)
+ {
+ if(!(leveltime&7))
+ S_StartSound(&plat->sector->soundorg, sfx_stnmov);
+ }
+
+
+ if(res == crushed && (!plat->crush))
+ {
+ plat->count = plat->wait;
+ plat->status = down;
+ S_StartSound(&plat->sector->soundorg, sfx_pstart);
+ }
+ else
+ {
+ if(res == pastdest)
+ {
+ plat->count = plat->wait;
+ plat->status = waiting;
+ S_StartSound(&plat->sector->soundorg, sfx_pstop);
+
+ switch(plat->type)
+ {
+ case blazeDWUS:
+ case downWaitUpStay:
+ case raiseAndChange:
+ case slowDWUS: // villsa [STRIFE]
+ case raiseToNearestAndChange:
+ P_RemoveActivePlat(plat);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+
+ case down:
+ res = T_MovePlane(plat->sector, plat->speed, plat->low, false, 0, -1);
+
+ // villsa [STRIFE]
+ if(plat->type == slowDWUS)
+ {
+ if(!(leveltime&7))
+ S_StartSound(&plat->sector->soundorg, sfx_stnmov);
+ }
+
+ if(res == pastdest)
+ {
+ plat->count = plat->wait;
+ plat->status = waiting;
+ S_StartSound(&plat->sector->soundorg,sfx_pstop);
+
+ // villsa [STRIFE]
+ if(plat->type == upWaitDownStay)
+ P_RemoveActivePlat(plat);
+ }
+ break;
+
+ case waiting:
+ if(!--plat->count)
+ {
+ if(plat->sector->floorheight == plat->low)
+ plat->status = up;
+ else
+ plat->status = down;
+ S_StartSound(&plat->sector->soundorg,sfx_pstart);
+ }
+
+ case in_stasis:
+ break;
+ }
+}
+
+
+//
+// EV_DoPlat
+//
+// Do Platforms "amount" is only used for SOME platforms.
+//
+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;
+
+ default:
+ break;
+ }
+
+ while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+
+ if (sec->specialdata)
+ continue;
+
+ // Find lowest & highest floors around sector
+ rtn = 1;
+ plat = Z_Malloc( sizeof(*plat), PU_LEVSPEC, 0);
+ P_AddThinker(&plat->thinker);
+
+ plat->type = type;
+ plat->sector = sec;
+ plat->sector->specialdata = plat;
+ plat->thinker.function.acp1 = (actionf_p1) T_PlatRaise;
+ plat->crush = false;
+ plat->tag = line->tag;
+
+ 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;
+
+ // NO MORE DAMAGE, IF APPLICABLE
+ sec->special = 0;
+
+ S_StartSound(&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(&sec->soundorg, sfx_stnmov);
+ break;
+
+ // villsa [STRIFE]
+ case upWaitDownStay:
+ plat->speed = PLATSPEED * 4;
+ plat->high = P_FindNextHighestFloor(sec, sec->floorheight);
+ plat->low = sec->floorheight;
+ plat->wait = TICRATE * PLATWAIT;
+ plat->status = up;
+ S_StartSound(&sec->soundorg, sfx_pstart);
+ 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 = TICRATE * PLATWAIT;
+ plat->status = down;
+ S_StartSound(&sec->soundorg, sfx_pstart);
+ break;
+
+ // villsa [STRIFE]
+ case slowDWUS:
+ plat->speed = PLATSPEED;
+ plat->low = P_FindLowestFloorSurrounding(sec);
+
+ if(plat->low > sec->floorheight)
+ plat->low = sec->floorheight;
+
+ plat->high = sec->floorheight;
+ plat->wait = TICRATE * (PLATWAIT * 10);
+ plat->status = down;
+ S_StartSound(&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 = TICRATE * PLATWAIT;
+ plat->status = down;
+ S_StartSound(&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 = TICRATE * PLATWAIT;
+ plat->status = P_Random() & 1;
+
+ S_StartSound(&sec->soundorg, sfx_pstart);
+ break;
+ }
+
+ P_AddActivePlat(plat);
+ }
+ return rtn;
+}
+
+
+//
+// P_ActivateInStasis
+//
+void P_ActivateInStasis(int tag)
+{
+ int i;
+
+ for(i = 0; i < MAXPLATS; i++)
+ if(activeplats[i]
+ && (activeplats[i])->tag == tag
+ && (activeplats[i])->status == in_stasis)
+ {
+ (activeplats[i])->status = (activeplats[i])->oldstatus;
+ (activeplats[i])->thinker.function.acp1
+ = (actionf_p1)T_PlatRaise;
+ }
+}
+
+//
+// EV_StopPlat
+//
+void EV_StopPlat(line_t* line)
+{
+ int j;
+
+ for(j = 0; j < MAXPLATS; j++)
+ if (activeplats[j]
+ && ((activeplats[j])->status != in_stasis)
+ && ((activeplats[j])->tag == line->tag))
+ {
+ (activeplats[j])->oldstatus = (activeplats[j])->status;
+ (activeplats[j])->status = in_stasis;
+ (activeplats[j])->thinker.function.acv = (actionf_v)NULL;
+ }
+}
+
+//
+// P_AddActivePlat
+//
+void P_AddActivePlat(plat_t* plat)
+{
+ int i;
+
+ for(i = 0; i < MAXPLATS; i++)
+ if (activeplats[i] == NULL)
+ {
+ activeplats[i] = plat;
+ return;
+ }
+
+ I_Error("P_AddActivePlat: no more plats!");
+}
+
+//
+// P_RemoveActivePlat
+//
+void P_RemoveActivePlat(plat_t* plat)
+{
+ int i;
+ for(i = 0; i < MAXPLATS; i++)
+ if(plat == activeplats[i])
+ {
+ (activeplats[i])->sector->specialdata = NULL;
+ P_RemoveThinker(&(activeplats[i])->thinker);
+ activeplats[i] = NULL;
+
+ return;
+ }
+
+ I_Error("P_RemoveActivePlat: can't find plat!");
+}
diff --git a/src/strife/p_pspr.c b/src/strife/p_pspr.c
new file mode 100644
index 00000000..80c53afd
--- /dev/null
+++ b/src/strife/p_pspr.c
@@ -0,0 +1,1012 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 "doomdef.h"
+#include "d_event.h"
+
+#include "deh_misc.h"
+
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+// State.
+#include "doomstat.h"
+
+// Data.
+#include "sounds.h"
+
+#include "p_pspr.h"
+
+#define LOWERSPEED FRACUNIT*6
+#define RAISESPEED FRACUNIT*6
+
+#define WEAPONBOTTOM 128*FRACUNIT
+#define WEAPONTOP 32*FRACUNIT
+
+
+
+//
+// P_SetPsprite
+//
+// [STRIFE]
+// villsa: Removed psprite sx, sy modification via misc1/2
+//
+void
+P_SetPsprite
+( player_t* player,
+ int position,
+ statenum_t stnum )
+{
+ pspdef_t* psp;
+ state_t* state;
+
+ psp = &player->psprites[position];
+
+ do
+ {
+ if (!stnum)
+ {
+ // object removed itself
+ psp->state = NULL;
+ break;
+ }
+
+ state = &states[stnum];
+ psp->state = state;
+ psp->tics = state->tics; // could be 0
+
+ // villsa [STRIFE] unused
+ /*if (state->misc1)
+ {
+ // coordinate set
+ psp->sx = state->misc1 << FRACBITS;
+ psp->sy = state->misc2 << FRACBITS;
+ }*/
+
+ // Call action routine.
+ // Modified handling.
+ if (state->action.acp2)
+ {
+ state->action.acp2(player, psp);
+ if (!psp->state)
+ break;
+ }
+
+ stnum = psp->state->nextstate;
+
+ } while (!psp->tics);
+ // an initial state of 0 could cycle through
+}
+
+// haleyjd 09/06/10: [STRIFE] Removed P_CalcSwing
+
+//
+// P_BringUpWeapon
+// Starts bringing the pending weapon up
+// from the bottom of the screen.
+// Uses player
+//
+// villsa [STRIFE] Modifications for Strife weapons
+//
+void P_BringUpWeapon (player_t* player)
+{
+ statenum_t newstate;
+
+ if (player->pendingweapon == wp_nochange)
+ player->pendingweapon = player->readyweapon;
+
+ if (player->pendingweapon == wp_flame)
+ S_StartSound (player->mo, sfx_flidl); // villsa [STRIFE] flame sounds
+
+ newstate = weaponinfo[player->pendingweapon].upstate;
+
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite (player, ps_weapon, newstate);
+
+ // villsa [STRIFE] set various flash states
+ if(player->pendingweapon == wp_elecbow)
+ P_SetPsprite(player, ps_flash, S_XBOW_10); // 31
+ else if(player->pendingweapon == wp_sigil && player->sigiltype)
+ P_SetPsprite(player, ps_flash, S_SIGH_00 + player->sigiltype); // 117
+ else
+ P_SetPsprite(player, ps_flash, S_NULL);
+
+ player->pendingweapon = wp_nochange;
+}
+
+//
+// P_CheckAmmo
+// Returns true if there is enough ammo to shoot.
+// If not, selects the next weapon to use.
+//
+// villsa [STRIFE] Changes to handle Strife weapons
+//
+boolean P_CheckAmmo (player_t* player)
+{
+ ammotype_t ammo;
+ int count;
+
+ ammo = weaponinfo[player->readyweapon].ammo;
+
+ // Minimal amount for one shot varies.
+ if (player->readyweapon == wp_torpedo)
+ count = 30;
+ else if (player->readyweapon == wp_mauler)
+ count = 20;
+ else
+ count = 1; // Regular.
+
+ // 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.
+ // Preferences are set here.
+
+ // villsa [STRIFE] new weapon preferences
+ if (player->weaponowned[wp_mauler] && player->ammo[am_cell] >= 20)
+ player->pendingweapon = wp_mauler;
+
+ else if(player->weaponowned[wp_rifle] && player->ammo[am_bullets])
+ player->pendingweapon = wp_rifle;
+
+ else if (player->weaponowned[wp_elecbow] && player->ammo[am_elecbolts])
+ player->pendingweapon = wp_elecbow;
+
+ else if (player->weaponowned[wp_missile] && player->ammo[am_missiles])
+ player->pendingweapon = wp_missile;
+
+ else if (player->weaponowned[wp_flame] && player->ammo[am_cell])
+ player->pendingweapon = wp_flame;
+
+ else if (player->weaponowned[wp_hegrenade] && player->ammo[am_hegrenades])
+ player->pendingweapon = wp_hegrenade;
+
+ else if (player->weaponowned[wp_poisonbow] && player->ammo[am_poisonbolts])
+ player->pendingweapon = wp_poisonbow;
+
+ else if (player->weaponowned[wp_wpgrenade] && player->ammo[am_wpgrenades])
+ player->pendingweapon = wp_wpgrenade;
+
+ // BUG: This will *never* be selected for an automatic switch because the
+ // normal Mauler is higher priority and uses less ammo.
+ else if (player->weaponowned[wp_torpedo] && player->ammo[am_cell] >= 30)
+ player->pendingweapon = wp_torpedo;
+
+ else
+ player->pendingweapon = wp_fist;
+
+
+ // Now set appropriate weapon overlay.
+ P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate);
+
+ return false;
+}
+
+
+//
+// P_FireWeapon.
+//
+// villsa [STRIFE] Changes for player state and weapons
+//
+void P_FireWeapon (player_t* player)
+{
+ statenum_t newstate;
+
+ if (!P_CheckAmmo (player))
+ return;
+
+ P_SetMobjState (player->mo, S_PLAY_05); // 292
+ newstate = weaponinfo[player->readyweapon].atkstate;
+ P_SetPsprite (player, ps_weapon, newstate);
+
+ // villsa [STRIFE] exclude these weapons from causing noise
+ if(player->readyweapon > wp_elecbow && player->readyweapon != wp_poisonbow)
+ P_NoiseAlert (player->mo, player->mo);
+}
+
+
+
+//
+// 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)
+{
+ statenum_t newstate;
+ int angle;
+
+ // get out of attack state
+ if (player->mo->state == &states[S_PLAY_05] || // 292
+ player->mo->state == &states[S_PLAY_06]) // 293
+ {
+ P_SetMobjState (player->mo, S_PLAY_00); // 287
+ }
+
+ // villsa [STRIFE] check for wp_flame instead of chainsaw
+ // haleyjd 09/06/10: fixed state (00 rather than 01)
+ if (player->readyweapon == wp_flame
+ && psp->state == &states[S_FLMT_00]) // 62
+ {
+ S_StartSound (player->mo, sfx_flidl);
+ }
+
+ // check for change
+ // if player is dead, put the weapon away
+ if (player->pendingweapon != wp_nochange || !player->health)
+ {
+ // change weapon
+ // (pending weapon should allready be validated)
+ newstate = weaponinfo[player->readyweapon].downstate;
+ P_SetPsprite (player, ps_weapon, newstate);
+ return;
+ }
+
+ // check for fire
+ // the missile launcher and torpedo do not auto fire
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ if ( !player->attackdown
+ || (player->readyweapon != wp_missile
+ && player->readyweapon != wp_torpedo)) // villsa [STRIFE] replace bfg with torpedo
+ {
+ player->attackdown = true;
+ P_FireWeapon (player);
+ return;
+ }
+ }
+ else
+ player->attackdown = false;
+
+ // bob the weapon based on movement speed
+ 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 )
+{
+
+ // 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);
+ }
+}
+
+//
+// A_CheckReload
+//
+void A_CheckReload(player_t* player, pspdef_t* psp)
+{
+ P_CheckAmmo(player);
+
+ // villsa [STRIFE] set animating sprite for crossbow
+ if(player->readyweapon == wp_elecbow)
+ P_SetPsprite(player, player->readyweapon, S_XBOW_10);
+}
+
+
+
+//
+// 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;
+
+ // don't bring weapon back up
+ return;
+ }
+
+ // 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);
+}
+
+
+
+//
+// A_GunFlash
+//
+void
+A_GunFlash
+( player_t* player,
+ pspdef_t* psp )
+{
+ P_SetMobjState (player->mo, S_PLAY_06);
+ P_SetPsprite (player,ps_flash,weaponinfo[player->readyweapon].flashstate);
+}
+
+
+
+//
+// WEAPON ATTACKS
+//
+
+
+//
+// A_Punch
+//
+
+void A_Punch(player_t* player, pspdef_t* psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+ int sound;
+ int stamina;
+ int t;
+
+ // villsa [STRIFE] new damage formula
+ // haleyjd 09/19/10: seriously corrected...
+ stamina = player->stamina;
+ damage = (P_Random() & ((stamina/10) + 7)) * ((stamina/10) + 2);
+
+ if(player->powers[pw_strength])
+ damage *= 10;
+
+ angle = player->mo->angle;
+ t = P_Random();
+ angle += (t - P_Random()) << 18;
+ slope = P_AimLineAttack (player->mo, angle, PLAYERMELEERANGE);
+ P_LineAttack (player->mo, angle, PLAYERMELEERANGE, slope, damage);
+
+ // turn to face target
+ if(linetarget)
+ {
+ // villsa [STRIFE] check for non-flesh types
+ if(linetarget->flags & MF_NOBLOOD)
+ sound = sfx_mtalht;
+ else
+ sound = sfx_meatht;
+
+ S_StartSound (player->mo, sound);
+ player->mo->angle = R_PointToAngle2 (player->mo->x,
+ player->mo->y,
+ linetarget->x,
+ linetarget->y);
+
+ // villsa [STRIFE] apply flag
+ player->mo->flags |= MF_JUSTATTACKED;
+
+ // villsa [STRIFE] do punch alert routine
+ P_DoPunchAlert(player->mo, linetarget);
+ }
+ else
+ S_StartSound (player->mo, sfx_swish);
+}
+
+
+//
+// A_FireFlameThrower
+//
+// villsa [STRIFE] new codepointer
+//
+void A_FireFlameThrower(player_t* player, pspdef_t* psp)
+{
+ mobj_t* mo;
+ int t;
+
+ P_SetMobjState(player->mo, S_PLAY_06);
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ t = P_Random();
+ player->mo->angle += (t - P_Random()) << 18;
+
+ mo = P_SpawnPlayerMissile(player->mo, MT_SFIREBALL);
+ mo->momz += (5*FRACUNIT);
+}
+
+//
+// A_FireMissile
+//
+// villsa [STRIFE] completly new compared to the original
+//
+void A_FireMissile(player_t* player, pspdef_t* psp)
+{
+ angle_t an;
+ int t;
+
+ // haleyjd 09/19/10: I previously missed an add op that meant it should be
+ // accuracy * 5, not 4. Checks out with other sources.
+ an = player->mo->angle;
+ t = P_Random();
+ player->mo->angle += (t - P_Random()) << (19 - (player->accuracy * 5 / 100));
+ P_SetMobjState(player->mo, S_PLAY_06);
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ P_SpawnPlayerMissile(player->mo, MT_MINIMISSLE);
+ player->mo->angle = an;
+}
+
+//
+// A_FireMauler2
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireMauler2(player_t* player, pspdef_t* pspr)
+{
+ P_SetMobjState(player->mo, S_PLAY_06);
+ P_DamageMobj(player->mo, player->mo, NULL, 20);
+ player->ammo[weaponinfo[player->readyweapon].ammo] -= 30;
+ P_SpawnPlayerMissile(player->mo, MT_TORPEDO);
+ P_Thrust(player, player->mo->angle + ANG180, 512000);
+}
+
+//
+// A_FireGrenade
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireGrenade(player_t* player, pspdef_t* pspr)
+{
+ mobjtype_t type;
+ mobj_t* mo;
+ state_t* st1;
+ state_t* st2;
+ angle_t an;
+ fixed_t radius;
+
+ // decide on what type of grenade to spawn
+ if(player->readyweapon == wp_hegrenade)
+ {
+ type = MT_HEGRENADE;
+ }
+ else if(player->readyweapon == wp_wpgrenade)
+ {
+ type = MT_PGRENADE;
+ }
+ else
+ {
+ type = MT_HEGRENADE;
+ fprintf(stderr, "Warning: A_FireGrenade used on wrong weapon!\n");
+ }
+
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+
+ // set flash frame
+ st1 = &states[(pspr->state - states) + weaponinfo[player->readyweapon].flashstate];
+ st2 = &states[weaponinfo[player->readyweapon].atkstate];
+ P_SetPsprite(player, ps_flash, st1 - st2);
+
+ player->mo->z += 32*FRACUNIT; // ugh
+ mo = P_SpawnMortar(player->mo, type);
+ player->mo->z -= 32*FRACUNIT; // ugh
+
+ // change momz based on player's pitch
+ mo->momz = FixedMul((player->pitch<<FRACBITS) / 160, mo->info->speed) + (8*FRACUNIT);
+ S_StartSound(mo, mo->info->seesound);
+
+ radius = mobjinfo[type].radius + player->mo->info->radius;
+ an = (player->mo->angle >> ANGLETOFINESHIFT);
+
+ mo->x += FixedMul(finecosine[an], radius + (4*FRACUNIT));
+ mo->y += FixedMul(finesine[an], radius + (4*FRACUNIT));
+
+ // shoot grenade from left or right side?
+ if(&states[weaponinfo[player->readyweapon].atkstate] == pspr->state)
+ an = (player->mo->angle - ANG90) >> ANGLETOFINESHIFT;
+ else
+ an = (player->mo->angle + ANG90) >> ANGLETOFINESHIFT;
+
+ mo->x += FixedMul((15*FRACUNIT), finecosine[an]);
+ mo->y += FixedMul((15*FRACUNIT), finesine[an]);
+
+ // set bounce flag
+ mo->flags |= MF_BOUNCE;
+}
+
+//
+// A_FireElectricBolt
+// villsa [STRIFE] - new codepointer
+//
+
+void A_FireElectricBolt(player_t* player, pspdef_t* pspr)
+{
+ angle_t an = player->mo->angle;
+ int t;
+
+ // haleyjd 09/19/10: Use 5 mul on accuracy here as well
+ t = P_Random();
+ player->mo->angle += (t - P_Random()) << (18 - (player->accuracy * 5 / 100));
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ P_SpawnPlayerMissile(player->mo, MT_ELECARROW);
+ player->mo->angle = an;
+ S_StartSound(player->mo, sfx_xbow);
+}
+
+//
+// A_FirePoisonBolt
+// villsa [STRIFE] - new codepointer
+//
+
+void A_FirePoisonBolt(player_t* player, pspdef_t* pspr)
+{
+ angle_t an = player->mo->angle;
+ int t;
+
+ // haleyjd 09/19/10: Use 5 mul on accuracy here as well
+ t = P_Random();
+ player->mo->angle += (t - P_Random()) << (18 - (player->accuracy * 5 / 100));
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ P_SpawnPlayerMissile(player->mo, MT_POISARROW);
+ player->mo->angle = an;
+ S_StartSound(player->mo, sfx_xbow);
+}
+
+//
+// P_BulletSlope
+// Sets a slope so a near miss is at aproximately
+// the height of the intended target
+//
+// haleyjd 09/06/10 [STRIFE] Modified with a little target hack...
+//
+fixed_t bulletslope;
+
+
+void P_BulletSlope (mobj_t *mo)
+{
+ angle_t an;
+
+ // see which target is to be aimed at
+ an = mo->angle;
+ bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+
+ if (!linetarget)
+ {
+ an += 1<<26;
+ bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an -= 2<<26;
+ bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+ }
+ }
+
+ // haleyjd 09/06/10: [STRIFE] Somebody added this here, and without it, you
+ // will get spurious crashing in routines such as P_LookForPlayers!
+ if(linetarget)
+ mo->target = linetarget;
+}
+
+
+//
+// P_GunShot
+//
+// [STRIFE] Modifications to support accuracy.
+//
+void
+P_GunShot
+( mobj_t* mo,
+ boolean accurate )
+{
+ angle_t angle;
+ int damage;
+
+ angle = mo->angle;
+
+ // villsa [STRIFE] apply player accuracy
+ // haleyjd 09/18/10: made some corrections: use 5x accuracy;
+ // eliminated order-of-evaluation dependency
+ if (!accurate)
+ {
+ int t = P_Random();
+ angle += (t - P_Random()) << (20 - ((mo->player->accuracy * 5) / 100));
+ }
+
+ // haleyjd 09/18/10 [STRIFE] corrected damage formula and moved down to
+ // preserve proper P_Random call order.
+ damage = 4 * (P_Random() % 3 + 1);
+
+ P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
+}
+
+//
+// A_FireRifle
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireRifle(player_t* player, pspdef_t* pspr)
+{
+ S_StartSound(player->mo, sfx_rifle);
+
+ if(player->ammo[weaponinfo[player->readyweapon].ammo])
+ {
+ P_SetMobjState(player->mo, S_PLAY_06); // 293
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ P_BulletSlope(player->mo);
+ P_GunShot(player->mo, !player->refire);
+ }
+}
+
+//
+// A_FireMauler1
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireMauler1(player_t* player, pspdef_t* pspr)
+{
+ int i;
+ angle_t angle;
+ int damage;
+
+ // haleyjd 09/18/10: Corrected ammo check to use >=
+ if(player->ammo[weaponinfo[player->readyweapon].ammo] >= 20)
+ {
+ player->ammo[weaponinfo[player->readyweapon].ammo] -= 20;
+ P_BulletSlope(player->mo);
+ S_StartSound(player->mo, sfx_pgrdat);
+
+ for(i = 0; i < 20; i++)
+ {
+ int t;
+ damage = 5*(P_Random ()%3+1);
+ angle = player->mo->angle;
+ t = P_Random();
+ angle += (t - P_Random()) << 19;
+ t = P_Random();
+ P_LineAttack(player->mo, angle, 2112*FRACUNIT,
+ bulletslope + ((t - P_Random())<<5), damage);
+ }
+ }
+}
+
+//
+// A_SigilSound
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_SigilSound(player_t* player, pspdef_t* pspr)
+{
+ S_StartSound(player->mo, sfx_siglup);
+ player->extralight = 2;
+
+}
+
+//
+// A_FireSigil
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_FireSigil(player_t* player, pspdef_t* pspr)
+{
+ mobj_t* mo;
+ angle_t an;
+ int i;
+
+ // keep info on armor because sigil does piercing damage
+ i = player->armortype;
+ player->armortype = 0;
+
+ // BUG: setting inflictor causes firing the Sigil to always push the player
+ // toward the east, no matter what direction he is facing.
+ P_DamageMobj(player->mo, player->mo, NULL, 4 * (player->sigiltype + 1));
+
+ // restore armor
+ player->armortype = i;
+
+ S_StartSound(player->mo, sfx_siglup);
+
+ switch(player->sigiltype)
+ {
+ // falling lightning bolts from the sky
+ case 0:
+ P_BulletSlope(player->mo);
+ if(linetarget)
+ {
+ // haleyjd 09/18/10: corrected z coordinate
+ mo = P_SpawnMobj(linetarget->x, linetarget->y, ONFLOORZ,
+ MT_SIGIL_A_GROUND);
+ mo->tracer = linetarget;
+ }
+ else
+ {
+ an = player->mo->angle>>ANGLETOFINESHIFT;
+ mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z,
+ MT_SIGIL_A_GROUND);
+ mo->momx += FixedMul((28*FRACUNIT), finecosine[an]);
+ mo->momy += FixedMul((28*FRACUNIT), finesine[an]);
+ }
+ mo->health = -1;
+ mo->target = player->mo;
+ break;
+
+ // simple projectile
+ case 1:
+ P_SpawnPlayerMissile(player->mo, MT_SIGIL_B_SHOT)->health = -1;
+ break;
+
+ // spread shot
+ case 2:
+ player->mo->angle -= ANG90; // starting at 270...
+ for(i = 0; i < 20; i++) // increment by 1/10 of 90, 20 times.
+ {
+ player->mo->angle += (ANG90 / 10);
+ mo = P_SpawnMortar(player->mo, MT_SIGIL_C_SHOT);
+ mo->health = -1;
+ mo->z = player->mo->z + (32*FRACUNIT);
+ }
+ player->mo->angle -= ANG90; // subtract off the extra 90
+ break;
+
+ // tracer attack
+ case 3:
+ P_BulletSlope(player->mo);
+ if(linetarget)
+ {
+ mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_D_SHOT);
+ mo->tracer = linetarget;
+ }
+ else
+ {
+ an = player->mo->angle >> ANGLETOFINESHIFT;
+ mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_D_SHOT);
+ mo->momx += FixedMul(mo->info->speed, finecosine[an]);
+ mo->momy += FixedMul(mo->info->speed, finesine[an]);
+ }
+ mo->health = -1;
+ break;
+
+ // mega blast
+ case 4:
+ mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_E_SHOT);
+ mo->health = -1;
+ if(!linetarget)
+ {
+ an = player->pitch >> ANGLETOFINESHIFT;
+ mo->momz += FixedMul(finesine[an], mo->info->speed);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+//
+// A_GunFlashThinker
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_GunFlashThinker(player_t* player, pspdef_t* pspr)
+{
+ if(player->readyweapon == wp_sigil && player->sigiltype)
+ P_SetPsprite(player, ps_flash, S_SIGH_00 + player->sigiltype);
+ else
+ P_SetPsprite(player, ps_flash, S_NULL);
+
+}
+
+
+//
+// ?
+//
+void A_Light0 (player_t *player, pspdef_t *psp)
+{
+ player->extralight = 0;
+}
+
+void A_Light1 (player_t *player, pspdef_t *psp)
+{
+ player->extralight = 1;
+}
+
+void A_Light2 (player_t *player, pspdef_t *psp)
+{
+ player->extralight = 2;
+}
+
+//
+// A_SigilShock
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_SigilShock (player_t *player, pspdef_t *psp)
+{
+ player->extralight = -3;
+}
+
+//
+// A_TorpedoExplode
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_TorpedoExplode(mobj_t* actor)
+{
+ int i;
+
+ actor->angle -= ANG180;
+
+ for(i = 0; i < 80; i++)
+ {
+ actor->angle += (ANG90 / 20);
+ P_SpawnMortar(actor, MT_TORPEDOSPREAD)->target = actor->target;
+ }
+}
+
+//
+// A_MaulerSound
+//
+// villsa [STRIFE] - new codepointer
+//
+void A_MaulerSound(player_t *player, pspdef_t *psp)
+{
+ int t;
+ S_StartSound(player->mo, sfx_proton);
+ t = P_Random();
+ psp->sx += (t - P_Random()) << 10;
+ t = P_Random();
+ psp->sy += (t - P_Random()) << 10;
+
+}
+
+
+//
+// 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)
+{
+ int i;
+ pspdef_t* psp;
+ state_t* state;
+
+ psp = &player->psprites[0];
+ for(i = 0; i < NUMPSPRITES; i++, psp++)
+ {
+ // a null state means not active
+ if((state = psp->state))
+ {
+ // drop tic count and possibly change state
+
+ // a -1 tic count never changes
+ if(psp->tics != -1)
+ {
+ psp->tics--;
+ if(!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;
+
+ // villsa [STRIFE] extra stuff for targeter
+ player->psprites[ps_targleft].sx =
+ (160*FRACUNIT) - ((100 - player->accuracy) << FRACBITS);
+
+ player->psprites[ps_targright].sx =
+ ((100 - player->accuracy) << FRACBITS) + (160*FRACUNIT);
+}
+
+
diff --git a/src/strife/p_pspr.h b/src/strife/p_pspr.h
new file mode 100644
index 00000000..64341b15
--- /dev/null
+++ b/src/strife/p_pspr.h
@@ -0,0 +1,87 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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"
+
+
+
+//
+// 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,
+ ps_targcenter, // villsa [STRIFE]
+ ps_targleft, // villsa [STRIFE]
+ ps_targright, // villsa [STRIFE]
+ NUMPSPRITES
+
+} psprnum_t;
+
+typedef struct
+{
+ state_t* state; // a NULL state means not active
+ int tics;
+ fixed_t sx;
+ fixed_t sy;
+
+} pspdef_t;
+
+typedef struct player_s *playerptr;
+
+// haleyjd [STRIFE] Exported
+void P_SetPsprite(playerptr player, int position, statenum_t stnum);
+
+#endif
diff --git a/src/strife/p_saveg.c b/src/strife/p_saveg.c
new file mode 100644
index 00000000..bc014de9
--- /dev/null
+++ b/src/strife/p_saveg.c
@@ -0,0 +1,2215 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+#include <stdlib.h>
+
+#include "dstrings.h"
+#include "deh_main.h"
+#include "i_system.h"
+#include "z_zone.h"
+#include "p_local.h"
+#include "p_saveg.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+#define SAVEGAME_EOF 0x1d
+
+// haleyjd 09/28/10: [STRIFE] VERSIONSIZE == 8
+#define VERSIONSIZE 8
+
+FILE *save_stream;
+int savegamelength;
+boolean savegame_error;
+
+// Get the filename of a temporary file to write the savegame to. After
+// the file has been successfully saved, it will be renamed to the
+// real file.
+
+char *P_TempSaveGameFile(void)
+{
+ static char *filename = NULL;
+
+ if (filename == NULL)
+ {
+ filename = malloc(strlen(savegamedir) + 32);
+ }
+
+ sprintf(filename, "%stemp.dsg", savegamedir);
+
+ return filename;
+}
+
+// Get the filename of the save game file to use for the specified slot.
+
+char *P_SaveGameFile(int slot)
+{
+ static char *filename = NULL;
+ char basename[32];
+
+ if (filename == NULL)
+ {
+ filename = malloc(strlen(savegamedir) + 32);
+ }
+
+ DEH_snprintf(basename, 32, SAVEGAMENAME "%d.dsg", slot);
+
+ sprintf(filename, "%s%s", savegamedir, basename);
+
+ return filename;
+}
+
+// Endian-safe integer read/write functions
+
+static byte saveg_read8(void)
+{
+ byte result;
+
+ if (fread(&result, 1, 1, save_stream) < 1)
+ {
+ if (!savegame_error)
+ {
+ fprintf(stderr, "saveg_read8: Unexpected end of file while "
+ "reading save game\n");
+
+ savegame_error = true;
+ }
+ }
+
+ return result;
+}
+
+static void saveg_write8(byte value)
+{
+ if (fwrite(&value, 1, 1, save_stream) < 1)
+ {
+ if (!savegame_error)
+ {
+ fprintf(stderr, "saveg_write8: Error while writing save game\n");
+
+ savegame_error = true;
+ }
+ }
+}
+
+static short saveg_read16(void)
+{
+ int result;
+
+ result = saveg_read8();
+ result |= saveg_read8() << 8;
+
+ return result;
+}
+
+static void saveg_write16(short value)
+{
+ saveg_write8(value & 0xff);
+ saveg_write8((value >> 8) & 0xff);
+}
+
+static int saveg_read32(void)
+{
+ int result;
+
+ result = saveg_read8();
+ result |= saveg_read8() << 8;
+ result |= saveg_read8() << 16;
+ result |= saveg_read8() << 24;
+
+ return result;
+}
+
+static void saveg_write32(int value)
+{
+ saveg_write8(value & 0xff);
+ saveg_write8((value >> 8) & 0xff);
+ saveg_write8((value >> 16) & 0xff);
+ saveg_write8((value >> 24) & 0xff);
+}
+
+// Pad to 4-byte boundaries
+
+static void saveg_read_pad(void)
+{
+ unsigned long pos;
+ int padding;
+ int i;
+
+ pos = ftell(save_stream);
+
+ padding = (4 - (pos & 3)) & 3;
+
+ for (i=0; i<padding; ++i)
+ {
+ saveg_read8();
+ }
+}
+
+static void saveg_write_pad(void)
+{
+ unsigned long pos;
+ int padding;
+ int i;
+
+ pos = ftell(save_stream);
+
+ padding = (4 - (pos & 3)) & 3;
+
+ for (i=0; i<padding; ++i)
+ {
+ saveg_write8(0);
+ }
+}
+
+
+// Pointers
+
+static void *saveg_readp(void)
+{
+ return (void *) saveg_read32();
+}
+
+static void saveg_writep(void *p)
+{
+ saveg_write32((int) p);
+}
+
+// Enum values are 32-bit integers.
+
+#define saveg_read_enum saveg_read32
+#define saveg_write_enum saveg_write32
+
+//
+// Structure read/write functions
+//
+
+//
+// mapthing_t
+//
+
+static void saveg_read_mapthing_t(mapthing_t *str)
+{
+ // short x;
+ str->x = saveg_read16();
+
+ // short y;
+ str->y = saveg_read16();
+
+ // short angle;
+ str->angle = saveg_read16();
+
+ // short type;
+ str->type = saveg_read16();
+
+ // short options;
+ str->options = saveg_read16();
+}
+
+static void saveg_write_mapthing_t(mapthing_t *str)
+{
+ // short x;
+ saveg_write16(str->x);
+
+ // short y;
+ saveg_write16(str->y);
+
+ // short angle;
+ saveg_write16(str->angle);
+
+ // short type;
+ saveg_write16(str->type);
+
+ // short options;
+ saveg_write16(str->options);
+}
+
+//
+// actionf_t
+//
+
+static void saveg_read_actionf_t(actionf_t *str)
+{
+ // actionf_p1 acp1;
+ str->acp1 = saveg_readp();
+}
+
+static void saveg_write_actionf_t(actionf_t *str)
+{
+ // actionf_p1 acp1;
+ saveg_writep(str->acp1);
+}
+
+//
+// think_t
+//
+// This is just an actionf_t.
+//
+
+#define saveg_read_think_t saveg_read_actionf_t
+#define saveg_write_think_t saveg_write_actionf_t
+
+//
+// thinker_t
+//
+
+static void saveg_read_thinker_t(thinker_t *str)
+{
+ // struct thinker_s* prev;
+ str->prev = saveg_readp();
+
+ // struct thinker_s* next;
+ str->next = saveg_readp();
+
+ // think_t function;
+ saveg_read_think_t(&str->function);
+}
+
+static void saveg_write_thinker_t(thinker_t *str)
+{
+ // struct thinker_s* prev;
+ saveg_writep(str->prev);
+
+ // struct thinker_s* next;
+ saveg_writep(str->next);
+
+ // think_t function;
+ saveg_write_think_t(&str->function);
+}
+
+//
+// mobj_t
+//
+// haleyjd 09/28/10: [STRIFE] Changed to match Strife binary mobj_t structure.
+//
+
+static void saveg_read_mobj_t(mobj_t *str)
+{
+ int pl;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // fixed_t x;
+ str->x = saveg_read32();
+
+ // fixed_t y;
+ str->y = saveg_read32();
+
+ // fixed_t z;
+ str->z = saveg_read32();
+
+ // struct mobj_s* snext;
+ str->snext = saveg_readp();
+
+ // struct mobj_s* sprev;
+ str->sprev = saveg_readp();
+
+ // angle_t angle;
+ str->angle = saveg_read32();
+
+ // spritenum_t sprite;
+ str->sprite = saveg_read_enum();
+
+ // int frame;
+ str->frame = saveg_read32();
+
+ // struct mobj_s* bnext;
+ str->bnext = saveg_readp();
+
+ // struct mobj_s* bprev;
+ str->bprev = saveg_readp();
+
+ // struct subsector_s* subsector;
+ str->subsector = saveg_readp();
+
+ // fixed_t floorz;
+ str->floorz = saveg_read32();
+
+ // fixed_t ceilingz;
+ str->ceilingz = saveg_read32();
+
+ // fixed_t radius;
+ str->radius = saveg_read32();
+
+ // fixed_t height;
+ str->height = saveg_read32();
+
+ // fixed_t momx;
+ str->momx = saveg_read32();
+
+ // fixed_t momy;
+ str->momy = saveg_read32();
+
+ // fixed_t momz;
+ str->momz = saveg_read32();
+
+ // int validcount;
+ str->validcount = saveg_read32();
+
+ // mobjtype_t type;
+ str->type = saveg_read_enum();
+
+ // mobjinfo_t* info;
+ str->info = saveg_readp();
+
+ // int tics;
+ str->tics = saveg_read32();
+
+ // state_t* state;
+ str->state = &states[saveg_read32()];
+
+ // int flags;
+ str->flags = saveg_read32();
+
+ // int health;
+ str->health = saveg_read32();
+
+ // int movedir;
+ str->movedir = saveg_read32();
+
+ // int movecount;
+ str->movecount = saveg_read32();
+
+ // struct mobj_s* target;
+ str->target = saveg_readp();
+
+ // int reactiontime;
+ str->reactiontime = saveg_read32();
+
+ // int threshold;
+ str->threshold = saveg_read32();
+
+ // struct player_s* player;
+ pl = saveg_read32();
+
+ if (pl > 0)
+ {
+ str->player = &players[pl - 1];
+ str->player->mo = str;
+ }
+ else
+ {
+ str->player = NULL;
+ }
+
+ // int lastlook;
+ str->lastlook = saveg_read32();
+
+ // mapthing_t spawnpoint;
+ saveg_read_mapthing_t(&str->spawnpoint);
+
+ // struct mobj_s* tracer;
+ str->tracer = saveg_readp();
+
+ // byte miscdata;
+ str->miscdata = saveg_read8(); // [STRIFE] Only change to mobj_t.
+}
+
+static void saveg_write_mobj_t(mobj_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // fixed_t x;
+ saveg_write32(str->x);
+
+ // fixed_t y;
+ saveg_write32(str->y);
+
+ // fixed_t z;
+ saveg_write32(str->z);
+
+ // struct mobj_s* snext;
+ saveg_writep(str->snext);
+
+ // struct mobj_s* sprev;
+ saveg_writep(str->sprev);
+
+ // angle_t angle;
+ saveg_write32(str->angle);
+
+ // spritenum_t sprite;
+ saveg_write_enum(str->sprite);
+
+ // int frame;
+ saveg_write32(str->frame);
+
+ // struct mobj_s* bnext;
+ saveg_writep(str->bnext);
+
+ // struct mobj_s* bprev;
+ saveg_writep(str->bprev);
+
+ // struct subsector_s* subsector;
+ saveg_writep(str->subsector);
+
+ // fixed_t floorz;
+ saveg_write32(str->floorz);
+
+ // fixed_t ceilingz;
+ saveg_write32(str->ceilingz);
+
+ // fixed_t radius;
+ saveg_write32(str->radius);
+
+ // fixed_t height;
+ saveg_write32(str->height);
+
+ // fixed_t momx;
+ saveg_write32(str->momx);
+
+ // fixed_t momy;
+ saveg_write32(str->momy);
+
+ // fixed_t momz;
+ saveg_write32(str->momz);
+
+ // int validcount;
+ saveg_write32(str->validcount);
+
+ // mobjtype_t type;
+ saveg_write_enum(str->type);
+
+ // mobjinfo_t* info;
+ saveg_writep(str->info);
+
+ // int tics;
+ saveg_write32(str->tics);
+
+ // state_t* state;
+ saveg_write32(str->state - states);
+
+ // int flags;
+ saveg_write32(str->flags);
+
+ // int health;
+ saveg_write32(str->health);
+
+ // int movedir;
+ saveg_write32(str->movedir);
+
+ // int movecount;
+ saveg_write32(str->movecount);
+
+ // struct mobj_s* target;
+ saveg_writep(str->target);
+
+ // int reactiontime;
+ saveg_write32(str->reactiontime);
+
+ // int threshold;
+ saveg_write32(str->threshold);
+
+ // struct player_s* player;
+ if (str->player)
+ {
+ saveg_write32(str->player - players + 1);
+ }
+ else
+ {
+ saveg_write32(0);
+ }
+
+ // int lastlook;
+ saveg_write32(str->lastlook);
+
+ // mapthing_t spawnpoint;
+ saveg_write_mapthing_t(&str->spawnpoint);
+
+ // struct mobj_s* tracer;
+ saveg_writep(str->tracer);
+
+ // byte miscdata;
+ saveg_write8(str->miscdata); // [STRIFE] Only change to mobj_t.
+}
+
+
+//
+// ticcmd_t
+//
+// haleyjd 09/28/10: [STRIFE] Modified for Strife binary ticcmd_t structure.
+//
+
+static void saveg_read_ticcmd_t(ticcmd_t *str)
+{
+ // signed char forwardmove;
+ str->forwardmove = saveg_read8();
+
+ // signed char sidemove;
+ str->sidemove = saveg_read8();
+
+ // short angleturn;
+ str->angleturn = saveg_read16();
+
+ // short consistancy;
+ // STRIFE-FIXME: throwing away top byte of consistancy until
+ // the true Strife ticcmd_t structure is available.
+ str->consistancy = (byte)saveg_read16();
+
+ // byte chatchar;
+ str->chatchar = saveg_read8();
+
+ // byte buttons;
+ str->buttons = saveg_read8();
+
+ // byte buttons2;
+ str->buttons2 = saveg_read8(); // [STRIFE]
+
+ // int inventory;
+ str->inventory = saveg_read32(); // [STRIFE]
+}
+
+static void saveg_write_ticcmd_t(ticcmd_t *str)
+{
+ // signed char forwardmove;
+ saveg_write8(str->forwardmove);
+
+ // signed char sidemove;
+ saveg_write8(str->sidemove);
+
+ // short angleturn;
+ saveg_write16(str->angleturn);
+
+ // short consistancy;
+ saveg_write16(str->consistancy);
+
+ // byte chatchar;
+ saveg_write8(str->chatchar);
+
+ // byte buttons;
+ saveg_write8(str->buttons);
+
+ // byte buttons2;
+ saveg_write8(str->buttons2); // [STRIFE]
+
+ // int inventory;
+ saveg_write32(str->inventory); // [STRIFE]
+}
+
+//
+// pspdef_t
+//
+
+static void saveg_read_pspdef_t(pspdef_t *str)
+{
+ int state;
+
+ // state_t* state;
+ state = saveg_read32();
+
+ if (state > 0)
+ {
+ str->state = &states[state];
+ }
+ else
+ {
+ str->state = NULL;
+ }
+
+ // int tics;
+ str->tics = saveg_read32();
+
+ // fixed_t sx;
+ str->sx = saveg_read32();
+
+ // fixed_t sy;
+ str->sy = saveg_read32();
+}
+
+static void saveg_write_pspdef_t(pspdef_t *str)
+{
+ // state_t* state;
+ if (str->state)
+ {
+ saveg_write32(str->state - states);
+ }
+ else
+ {
+ saveg_write32(0);
+ }
+
+ // int tics;
+ saveg_write32(str->tics);
+
+ // fixed_t sx;
+ saveg_write32(str->sx);
+
+ // fixed_t sy;
+ saveg_write32(str->sy);
+}
+
+//
+// inventory_t
+//
+// haleyjd 09/28/10: [STRIFE] handle inventory input/output
+//
+
+static void saveg_read_inventory_t(inventory_t *str)
+{
+ //int sprite;
+ str->sprite = saveg_read32();
+
+ //int type;
+ str->type = saveg_read32();
+
+ //int amount;
+ str->amount = saveg_read32();
+}
+
+static void saveg_write_inventory_t(inventory_t *str)
+{
+ saveg_write32(str->sprite);
+ saveg_write32(str->type);
+ saveg_write32(str->amount);
+}
+
+//
+// player_t
+//
+// haleyjd 09/28/10: [STRIFE] Modified for Strife binary player_t structure.
+//
+
+static void saveg_read_player_t(player_t *str)
+{
+ int i;
+
+ // mobj_t* mo;
+ str->mo = saveg_readp();
+
+ // playerstate_t playerstate;
+ str->playerstate = saveg_read_enum();
+
+ // ticcmd_t cmd;
+ saveg_read_ticcmd_t(&str->cmd);
+
+ // fixed_t viewz;
+ str->viewz = saveg_read32();
+
+ // fixed_t viewheight;
+ str->viewheight = saveg_read32();
+
+ // fixed_t deltaviewheight;
+ str->deltaviewheight = saveg_read32();
+
+ // fixed_t bob;
+ str->bob = saveg_read32();
+
+ // int health;
+ str->health = saveg_read32();
+
+ // int armorpoints;
+ str->armorpoints = saveg_read16(); // [STRIFE] 32 -> 16
+
+ // int armortype;
+ str->armortype = saveg_read16(); // [STRIFE] 32 -> 16
+
+ // int powers[NUMPOWERS];
+ for (i=0; i<NUMPOWERS; ++i)
+ {
+ str->powers[i] = saveg_read32();
+ }
+
+ // int sigiltype;
+ str->sigiltype = saveg_read32(); // [STRIFE]
+
+ // int nukagecount;
+ str->nukagecount = saveg_read32(); // [STRIFE]
+
+ // int questflags;
+ str->questflags = saveg_read32(); // [STRIFE]
+
+ // int pitch;
+ str->pitch = saveg_read32(); // [STRIFE]
+
+ // int centerview;
+ str->centerview = saveg_read32(); // [STRIFE]
+
+ // inventory_t inventory[NUMINVENTORY];
+ for(i = 0; i < NUMINVENTORY; i++)
+ {
+ saveg_read_inventory_t(&(str->inventory[i])); // [STRIFE]
+ }
+
+ // int st_update;
+ str->st_update = saveg_read32(); // [STRIFE]
+
+ // short numinventory;
+ str->numinventory = saveg_read16(); // [STRIFE]
+
+ // short inventorycursor;
+ str->inventorycursor = saveg_read16(); // [STRIFE]
+
+ // short accuracy;
+ str->accuracy = saveg_read16(); // [STRIFE]
+
+ // short stamina;
+ str->stamina = saveg_read16(); // [STRIFE]
+
+ // boolean cards[NUMCARDS];
+ for (i=0; i<NUMCARDS; ++i)
+ {
+ str->cards[i] = saveg_read32();
+ }
+
+ // boolean backpack;
+ str->backpack = saveg_read32();
+
+ // int attackdown;
+ str->attackdown = saveg_read32();
+
+ // int usedown;
+ str->usedown = saveg_read32();
+
+ // int inventorydown;
+ str->inventorydown = saveg_read32(); // [STRIFE]
+
+ // int frags[MAXPLAYERS];
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ str->frags[i] = saveg_read32();
+ }
+
+ // weapontype_t readyweapon;
+ str->readyweapon = saveg_read_enum();
+
+ // weapontype_t pendingweapon;
+ str->pendingweapon = saveg_read_enum();
+
+ // boolean weaponowned[NUMWEAPONS];
+ for (i=0; i<NUMWEAPONS; ++i)
+ {
+ str->weaponowned[i] = saveg_read32();
+ }
+
+ // int ammo[NUMAMMO];
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ str->ammo[i] = saveg_read32();
+ }
+
+ // int maxammo[NUMAMMO];
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ str->maxammo[i] = saveg_read32();
+ }
+
+ // int cheats;
+ str->cheats = saveg_read32();
+
+ // int refire;
+ str->refire = saveg_read32();
+
+ // short killcount;
+ str->killcount = saveg_read16(); // [STRIFE] 32 -> 16
+
+ // haleyjd 08/30/10 [STRIFE] No itemcount.
+ // int itemcount;
+ //str->itemcount = saveg_read32();
+
+ // haleyjd 08/30/10 [STRIFE] No secretcount.
+ // int secretcount;
+ //str->secretcount = saveg_read32();
+
+ // char* message;
+ str->message = saveg_readp();
+
+ // int damagecount;
+ str->damagecount = saveg_read32();
+
+ // int bonuscount;
+ str->bonuscount = saveg_read32();
+
+ // mobj_t* attacker;
+ str->attacker = saveg_readp();
+
+ // int extralight;
+ str->extralight = saveg_read32();
+
+ // int fixedcolormap;
+ str->fixedcolormap = saveg_read32();
+
+ // int colormap; - [STRIFE] no such field
+ //str->colormap = saveg_read32();
+
+ // short allegiance;
+ str->allegiance = saveg_read16(); // [STRIFE]
+
+ // pspdef_t psprites[NUMPSPRITES];
+ for (i=0; i<NUMPSPRITES; ++i)
+ {
+ saveg_read_pspdef_t(&str->psprites[i]);
+ }
+
+ // int mapstate[40];
+ for(i = 0; i < 40; ++i) // [STRIFE]
+ {
+ str->mapstate[i] = saveg_read32();
+ }
+
+ // haleyjd 08/30/10: [STRIFE] No intermission, no didsecret.
+ // boolean didsecret;
+ //str->didsecret = saveg_read32();
+}
+
+static void saveg_write_player_t(player_t *str)
+{
+ int i;
+
+ // mobj_t* mo;
+ saveg_writep(str->mo);
+
+ // playerstate_t playerstate;
+ saveg_write_enum(str->playerstate);
+
+ // ticcmd_t cmd;
+ saveg_write_ticcmd_t(&str->cmd);
+
+ // fixed_t viewz;
+ saveg_write32(str->viewz);
+
+ // fixed_t viewheight;
+ saveg_write32(str->viewheight);
+
+ // fixed_t deltaviewheight;
+ saveg_write32(str->deltaviewheight);
+
+ // fixed_t bob;
+ saveg_write32(str->bob);
+
+ // int health;
+ saveg_write32(str->health);
+
+ // int armorpoints;
+ saveg_write16(str->armorpoints); // [STRIFE] 32 -> 16
+
+ // int armortype;
+ saveg_write16(str->armortype); // [STRIFE] 32 -> 16
+
+ // int powers[NUMPOWERS];
+ for (i=0; i<NUMPOWERS; ++i)
+ {
+ saveg_write32(str->powers[i]);
+ }
+
+ // int sigiltype;
+ saveg_write32(str->sigiltype); // [STRIFE]
+
+ // int nukagecount;
+ saveg_write32(str->nukagecount); // [STRIFE]
+
+ // int questflags;
+ saveg_write32(str->questflags); // [STRIFE]
+
+ // int pitch;
+ saveg_write32(str->pitch); // [STRIFE]
+
+ // int centerview;
+ saveg_write32(str->centerview); // [STRIFE]
+
+ // inventory_t inventory[NUMINVENTORY];
+ for(i = 0; i < NUMINVENTORY; ++i) // [STRIFE]
+ {
+ saveg_write_inventory_t(&str->inventory[i]);
+ }
+
+ // int st_update;
+ saveg_write32(str->st_update); // [STRIFE]
+
+ // short numinventory;
+ saveg_write16(str->numinventory); // [STRIFE]
+
+ // short inventorycursor;
+ saveg_write16(str->inventorycursor); // [STRIFE]
+
+ // short accuracy;
+ saveg_write16(str->accuracy); // [STRIFE]
+
+ // short stamina;
+ saveg_write16(str->stamina); // [STRIFE]
+
+ // boolean cards[NUMCARDS];
+ for (i=0; i<NUMCARDS; ++i)
+ {
+ saveg_write32(str->cards[i]);
+ }
+
+ // boolean backpack;
+ saveg_write32(str->backpack);
+
+ // int attackdown;
+ saveg_write32(str->attackdown);
+
+ // int usedown;
+ saveg_write32(str->usedown);
+
+ // int inventorydown;
+ saveg_write32(str->inventorydown); // [STRIFE]
+
+ // int frags[MAXPLAYERS];
+ for (i=0; i<MAXPLAYERS; ++i)
+ {
+ saveg_write32(str->frags[i]);
+ }
+
+ // weapontype_t readyweapon;
+ saveg_write_enum(str->readyweapon);
+
+ // weapontype_t pendingweapon;
+ saveg_write_enum(str->pendingweapon);
+
+ // boolean weaponowned[NUMWEAPONS];
+ for (i=0; i<NUMWEAPONS; ++i)
+ {
+ saveg_write32(str->weaponowned[i]);
+ }
+
+ // int ammo[NUMAMMO];
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ saveg_write32(str->ammo[i]);
+ }
+
+ // int maxammo[NUMAMMO];
+ for (i=0; i<NUMAMMO; ++i)
+ {
+ saveg_write32(str->maxammo[i]);
+ }
+
+
+ // int cheats;
+ saveg_write32(str->cheats);
+
+ // int refire;
+ saveg_write32(str->refire);
+
+ // short killcount;
+ saveg_write16(str->killcount); // [STRIFE] 32 -> 16
+
+ // haleyjd 08/30/10 [STRIFE] No itemcount
+ // int itemcount;
+ //saveg_write32(str->itemcount);
+
+ // haleyjd 08/30/10 [STRIFE] No secretcount
+ // int secretcount;
+ //saveg_write32(str->secretcount);
+
+ // char* message;
+ saveg_writep(str->message);
+
+ // int damagecount;
+ saveg_write32(str->damagecount);
+
+ // int bonuscount;
+ saveg_write32(str->bonuscount);
+
+ // mobj_t* attacker;
+ saveg_writep(str->attacker);
+
+ // int extralight;
+ saveg_write32(str->extralight);
+
+ // int fixedcolormap;
+ saveg_write32(str->fixedcolormap);
+
+ // int colormap; [STRIFE] no such field
+ //saveg_write32(str->colormap);
+
+ // short allegiance;
+ saveg_write16(str->allegiance); // [STRIFE]
+
+ // pspdef_t psprites[NUMPSPRITES];
+ for (i=0; i<NUMPSPRITES; ++i)
+ {
+ saveg_write_pspdef_t(&str->psprites[i]);
+ }
+
+ // int mapstate[40];
+ for(i = 0; i < 40; ++i) // [STRIFE]
+ {
+ saveg_write32(str->mapstate[i]);
+ }
+
+ // haleyjd 08/30/10: [STRIFE] No intermission, no secret.
+ // boolean didsecret;
+ //saveg_write32(str->didsecret);
+}
+
+
+//
+// ceiling_t
+//
+
+static void saveg_read_ceiling_t(ceiling_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // ceiling_e type;
+ str->type = saveg_read_enum();
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // fixed_t bottomheight;
+ str->bottomheight = saveg_read32();
+
+ // fixed_t topheight;
+ str->topheight = saveg_read32();
+
+ // fixed_t speed;
+ str->speed = saveg_read32();
+
+ // boolean crush;
+ str->crush = saveg_read32();
+
+ // int direction;
+ str->direction = saveg_read32();
+
+ // int tag;
+ str->tag = saveg_read32();
+
+ // int olddirection;
+ str->olddirection = saveg_read32();
+}
+
+static void saveg_write_ceiling_t(ceiling_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // ceiling_e type;
+ saveg_write_enum(str->type);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // fixed_t bottomheight;
+ saveg_write32(str->bottomheight);
+
+ // fixed_t topheight;
+ saveg_write32(str->topheight);
+
+ // fixed_t speed;
+ saveg_write32(str->speed);
+
+ // boolean crush;
+ saveg_write32(str->crush);
+
+ // int direction;
+ saveg_write32(str->direction);
+
+ // int tag;
+ saveg_write32(str->tag);
+
+ // int olddirection;
+ saveg_write32(str->olddirection);
+}
+
+//
+// vldoor_t
+//
+// haleyjd 09/28/10: [STRIFE] Modified for Strife binary vldoor_t structure.
+//
+
+static void saveg_read_vldoor_t(vldoor_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // vldoor_e type;
+ str->type = saveg_read_enum();
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // fixed_t topheight;
+ str->topheight = saveg_read32();
+
+ // fixed_t speed;
+ str->speed = saveg_read32();
+
+ // int direction;
+ str->direction = saveg_read32();
+
+ // int topwait;
+ str->topwait = saveg_read32();
+
+ // int topcountdown;
+ str->topcountdown = saveg_read32();
+
+ // villsa [STRIFE] new field - sound to play when opening
+ //int opensound;
+ str->opensound = saveg_read32();
+
+ // villsa [STRIFE] new field - sound to play when closing
+ //int closesound;
+ str->closesound = saveg_read32();
+}
+
+static void saveg_write_vldoor_t(vldoor_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // vldoor_e type;
+ saveg_write_enum(str->type);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // fixed_t topheight;
+ saveg_write32(str->topheight);
+
+ // fixed_t speed;
+ saveg_write32(str->speed);
+
+ // int direction;
+ saveg_write32(str->direction);
+
+ // int topwait;
+ saveg_write32(str->topwait);
+
+ // int topcountdown;
+ saveg_write32(str->topcountdown);
+
+ // villsa [STRIFE] new field - sound to play when opening
+ //int opensound;
+ saveg_write32(str->opensound);
+
+ // villsa [STRIFE] new field - sound to play when closing
+ //int closesound;
+ saveg_write32(str->closesound);
+}
+
+//
+// slidedoor_t [STRIFE]: new thinker type
+//
+
+static void saveg_read_slidedoor_t(slidedoor_t *str)
+{
+ int sector;
+ int line;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sdt_e type;
+ str->type = saveg_read_enum();
+
+ // line_t *line1;
+ line = saveg_read32();
+ str->line1 = &lines[line];
+
+ // line_t *line2;
+ line = saveg_read32();
+ str->line2 = &lines[line];
+
+ // int frame;
+ str->frame = saveg_read32();
+
+ // int whichDoorIndex;
+ str->whichDoorIndex = saveg_read32();
+
+ // int timer;
+ str->timer = saveg_read32();
+
+ // sector_t *frontsector;
+ sector = saveg_read32();
+ str->frontsector = &sectors[sector];
+
+ // sd_e status;
+ str->status = saveg_read_enum();
+}
+
+static void saveg_write_slidedoor_t(slidedoor_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sdt_e type;
+ saveg_write_enum(str->type);
+
+ // line_t *line1;
+ saveg_write32(str->line1 - lines);
+
+ // line_t *line2;
+ saveg_write32(str->line2 - lines);
+
+ // int frame;
+ saveg_write32(str->frame);
+
+ // int whichDoorIndex;
+ saveg_write32(str->whichDoorIndex);
+
+ // int timer;
+ saveg_write32(str->timer);
+
+ // sector_t *frontsector;
+ saveg_write32(str->frontsector - sectors);
+
+ // sd_e status;
+ saveg_write_enum(str->status);
+}
+
+//
+// floormove_t
+//
+
+static void saveg_read_floormove_t(floormove_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // floor_e type;
+ str->type = saveg_read_enum();
+
+ // boolean crush;
+ str->crush = saveg_read32();
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // int direction;
+ str->direction = saveg_read32();
+
+ // int newspecial;
+ str->newspecial = saveg_read32();
+
+ // short texture;
+ str->texture = saveg_read16();
+
+ // fixed_t floordestheight;
+ str->floordestheight = saveg_read32();
+
+ // fixed_t speed;
+ str->speed = saveg_read32();
+}
+
+static void saveg_write_floormove_t(floormove_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // floor_e type;
+ saveg_write_enum(str->type);
+
+ // boolean crush;
+ saveg_write32(str->crush);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // int direction;
+ saveg_write32(str->direction);
+
+ // int newspecial;
+ saveg_write32(str->newspecial);
+
+ // short texture;
+ saveg_write16(str->texture);
+
+ // fixed_t floordestheight;
+ saveg_write32(str->floordestheight);
+
+ // fixed_t speed;
+ saveg_write32(str->speed);
+}
+
+//
+// plat_t
+//
+
+static void saveg_read_plat_t(plat_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // fixed_t speed;
+ str->speed = saveg_read32();
+
+ // fixed_t low;
+ str->low = saveg_read32();
+
+ // fixed_t high;
+ str->high = saveg_read32();
+
+ // int wait;
+ str->wait = saveg_read32();
+
+ // int count;
+ str->count = saveg_read32();
+
+ // plat_e status;
+ str->status = saveg_read_enum();
+
+ // plat_e oldstatus;
+ str->oldstatus = saveg_read_enum();
+
+ // boolean crush;
+ str->crush = saveg_read32();
+
+ // int tag;
+ str->tag = saveg_read32();
+
+ // plattype_e type;
+ str->type = saveg_read_enum();
+}
+
+static void saveg_write_plat_t(plat_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // fixed_t speed;
+ saveg_write32(str->speed);
+
+ // fixed_t low;
+ saveg_write32(str->low);
+
+ // fixed_t high;
+ saveg_write32(str->high);
+
+ // int wait;
+ saveg_write32(str->wait);
+
+ // int count;
+ saveg_write32(str->count);
+
+ // plat_e status;
+ saveg_write_enum(str->status);
+
+ // plat_e oldstatus;
+ saveg_write_enum(str->oldstatus);
+
+ // boolean crush;
+ saveg_write32(str->crush);
+
+ // int tag;
+ saveg_write32(str->tag);
+
+ // plattype_e type;
+ saveg_write_enum(str->type);
+}
+
+//
+// lightflash_t
+//
+
+static void saveg_read_lightflash_t(lightflash_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // int count;
+ str->count = saveg_read32();
+
+ // int maxlight;
+ str->maxlight = saveg_read32();
+
+ // int minlight;
+ str->minlight = saveg_read32();
+
+ // int maxtime;
+ str->maxtime = saveg_read32();
+
+ // int mintime;
+ str->mintime = saveg_read32();
+}
+
+static void saveg_write_lightflash_t(lightflash_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // int count;
+ saveg_write32(str->count);
+
+ // int maxlight;
+ saveg_write32(str->maxlight);
+
+ // int minlight;
+ saveg_write32(str->minlight);
+
+ // int maxtime;
+ saveg_write32(str->maxtime);
+
+ // int mintime;
+ saveg_write32(str->mintime);
+}
+
+//
+// strobe_t
+//
+
+static void saveg_read_strobe_t(strobe_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // int count;
+ str->count = saveg_read32();
+
+ // int minlight;
+ str->minlight = saveg_read32();
+
+ // int maxlight;
+ str->maxlight = saveg_read32();
+
+ // int darktime;
+ str->darktime = saveg_read32();
+
+ // int brighttime;
+ str->brighttime = saveg_read32();
+}
+
+static void saveg_write_strobe_t(strobe_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // int count;
+ saveg_write32(str->count);
+
+ // int minlight;
+ saveg_write32(str->minlight);
+
+ // int maxlight;
+ saveg_write32(str->maxlight);
+
+ // int darktime;
+ saveg_write32(str->darktime);
+
+ // int brighttime;
+ saveg_write32(str->brighttime);
+}
+
+//
+// glow_t
+//
+
+static void saveg_read_glow_t(glow_t *str)
+{
+ int sector;
+
+ // thinker_t thinker;
+ saveg_read_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ sector = saveg_read32();
+ str->sector = &sectors[sector];
+
+ // int minlight;
+ str->minlight = saveg_read32();
+
+ // int maxlight;
+ str->maxlight = saveg_read32();
+
+ // int direction;
+ str->direction = saveg_read32();
+}
+
+static void saveg_write_glow_t(glow_t *str)
+{
+ // thinker_t thinker;
+ saveg_write_thinker_t(&str->thinker);
+
+ // sector_t* sector;
+ saveg_write32(str->sector - sectors);
+
+ // int minlight;
+ saveg_write32(str->minlight);
+
+ // int maxlight;
+ saveg_write32(str->maxlight);
+
+ // int direction;
+ saveg_write32(str->direction);
+}
+
+//
+// Write the header for a savegame
+//
+// haleyjd 09/28/10: [STRIFE] numerous modifications.
+//
+
+void P_WriteSaveGameHeader(char *description)
+{
+ char name[VERSIONSIZE];
+ int i;
+
+ /*
+ [STRIFE] This is in the "NAME" file in a Strife save directory.
+ for (i=0; description[i] != '\0'; ++i)
+ saveg_write8(description[i]);
+ for (; i<SAVESTRINGSIZE; ++i)
+ saveg_write8(0);
+ */
+
+ memset (name,0,sizeof(name));
+ sprintf (name,"ver %i",STRIFE_VERSION);
+
+ for (i=0; i<VERSIONSIZE; ++i)
+ saveg_write8(name[i]);
+
+ saveg_write8(gameskill);
+
+ // [STRIFE] This information is implicit in the file being loaded.
+ //saveg_write8(gameepisode);
+ //saveg_write8(gamemap);
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ saveg_write8(playeringame[i]);
+
+ saveg_write8((leveltime >> 16) & 0xff);
+ saveg_write8((leveltime >> 8) & 0xff);
+ saveg_write8(leveltime & 0xff);
+}
+
+//
+// Read the header for a savegame
+//
+
+boolean P_ReadSaveGameHeader(void)
+{
+ int i;
+ byte a, b, c;
+ char vcheck[VERSIONSIZE];
+ char read_vcheck[VERSIONSIZE];
+
+ // skip the description field
+ /*
+ for (i=0; i<SAVESTRINGSIZE; ++i)
+ saveg_read8();
+ */
+
+ for (i=0; i<VERSIONSIZE; ++i)
+ read_vcheck[i] = saveg_read8();
+
+ memset (vcheck,0,sizeof(vcheck));
+ sprintf (vcheck,"ver %i",STRIFE_VERSION);
+ if (strcmp(read_vcheck, vcheck) != 0)
+ return false; // bad version
+
+ gameskill = saveg_read8();
+
+ // [STRIFE] This info is implicit in the file being read.
+ //gameepisode = saveg_read8();
+ //gamemap = saveg_read8();
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ playeringame[i] = saveg_read8();
+
+ // get the times
+ a = saveg_read8();
+ b = saveg_read8();
+ c = saveg_read8();
+ leveltime = (a<<16) + (b<<8) + c;
+
+ return true;
+}
+
+//
+// Read the end of file marker. Returns true if read successfully.
+//
+
+boolean P_ReadSaveGameEOF(void)
+{
+ int value;
+
+ value = saveg_read8();
+
+ return value == SAVEGAME_EOF;
+}
+
+//
+// Write the end of file marker
+//
+
+void P_WriteSaveGameEOF(void)
+{
+ saveg_write8(SAVEGAME_EOF);
+}
+
+//
+// P_ArchivePlayers
+//
+// [STRIFE] Verified unmodified.
+//
+void P_ArchivePlayers (void)
+{
+ int i;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ saveg_write_pad();
+
+ saveg_write_player_t(&players[i]);
+ }
+}
+
+
+
+//
+// P_UnArchivePlayers
+//
+// [STRIFE] Verified unmodified.
+//
+void P_UnArchivePlayers (boolean userload)
+{
+ int i;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ player_t dummy;
+
+ if (!playeringame[i])
+ continue;
+
+ saveg_read_pad();
+
+ // haleyjd [STRIFE]: not exactly how vanilla did it, but this is
+ // necessary because of Choco's change to the savegame code which
+ // reads it directly from file. When not a userload, all the player_t
+ // data loaded from the save is thrown away.
+ if(userload)
+ {
+ saveg_read_player_t(&players[i]);
+ players[i].mo = NULL;
+ }
+ else
+ saveg_read_player_t(&dummy);
+
+ // will be set when unarc thinker
+ players[i].message = NULL;
+ players[i].attacker = NULL;
+ }
+}
+
+
+//
+// P_ArchiveWorld
+//
+// haleyjd 09/28/10: [STRIFE] Minor modifications.
+//
+void P_ArchiveWorld (void)
+{
+ int i;
+ int j;
+ sector_t* sec;
+ line_t* li;
+ side_t* si;
+
+ // do sectors
+ for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
+ {
+ saveg_write16(sec->floorheight >> FRACBITS);
+ saveg_write16(sec->ceilingheight >> FRACBITS);
+ saveg_write16(sec->floorpic);
+ //saveg_write16(sec->ceilingpic); [STRIFE] not saved.
+ saveg_write16(sec->lightlevel);
+ saveg_write16(sec->special); // needed?
+ //saveg_write16(sec->tag); // needed? [STRIFE] not saved.
+ }
+
+
+ // do lines
+ for (i=0, li = lines ; i<numlines ; i++,li++)
+ {
+ saveg_write16(li->flags);
+ saveg_write16(li->special);
+ //saveg_write16(li->tag); [STRIFE] not saved.
+ for (j=0 ; j<2 ; j++)
+ {
+ if (li->sidenum[j] == -1)
+ continue;
+
+ si = &sides[li->sidenum[j]];
+
+ // [STRIFE] offsets not saved.
+ //saveg_write16(si->textureoffset >> FRACBITS);
+ //saveg_write16(si->rowoffset >> FRACBITS);
+ saveg_write16(si->toptexture);
+ saveg_write16(si->bottomtexture);
+ saveg_write16(si->midtexture);
+ }
+ }
+}
+
+
+
+//
+// P_UnArchiveWorld
+//
+void P_UnArchiveWorld (void)
+{
+ int i;
+ int j;
+ sector_t* sec;
+ line_t* li;
+ side_t* si;
+
+ // do sectors
+ for (i=0, sec = sectors ; i<numsectors ; i++,sec++)
+ {
+ sec->floorheight = saveg_read16() << FRACBITS;
+ sec->ceilingheight = saveg_read16() << FRACBITS;
+ sec->floorpic = saveg_read16();
+ //sec->ceilingpic = saveg_read16(); [STRIFE] not saved
+ sec->lightlevel = saveg_read16();
+ sec->special = saveg_read16(); // needed?
+ //sec->tag = saveg_read16(); // needed? [STRIFE] not saved
+ sec->specialdata = 0;
+ sec->soundtarget = 0;
+ }
+
+ // do lines
+ for (i=0, li = lines ; i<numlines ; i++,li++)
+ {
+ li->flags = saveg_read16();
+ li->special = saveg_read16();
+ //li->tag = saveg_read16(); [STRIFE] not saved
+ for (j=0 ; j<2 ; j++)
+ {
+ if (li->sidenum[j] == -1)
+ continue;
+ si = &sides[li->sidenum[j]];
+ // [STRIFE] offsets not saved.
+ //si->textureoffset = saveg_read16() << FRACBITS;
+ //si->rowoffset = saveg_read16() << FRACBITS;
+ si->toptexture = saveg_read16();
+ si->bottomtexture = saveg_read16();
+ si->midtexture = saveg_read16();
+ }
+ }
+}
+
+
+
+
+
+//
+// Thinkers
+//
+typedef enum
+{
+ tc_end,
+ tc_mobj
+
+} thinkerclass_t;
+
+
+//
+// P_ArchiveThinkers
+//
+// [STRIFE] Verified unmodified.
+//
+void P_ArchiveThinkers (void)
+{
+ thinker_t* th;
+
+ // save off the current thinkers
+ for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
+ {
+ if (th->function.acp1 == (actionf_p1)P_MobjThinker)
+ {
+ saveg_write8(tc_mobj);
+ saveg_write_pad();
+ saveg_write_mobj_t((mobj_t *) th);
+
+ continue;
+ }
+
+ // haleyjd: This may seem mysterious but in the DOOM prebeta,
+ // different types of things used different thinker functions.
+ // Those would have all been handled here and this message is
+ // probably a relic of that old system, not to mention the odd
+ // name of this function, and use of an enumeration with only
+ // two values in it.
+
+ // I_Error ("P_ArchiveThinkers: Unknown thinker function");
+ }
+
+ // add a terminating marker
+ saveg_write8(tc_end);
+}
+
+
+
+//
+// P_UnArchiveThinkers
+//
+void P_UnArchiveThinkers (void)
+{
+ byte tclass;
+ thinker_t* currentthinker;
+ thinker_t* next;
+ mobj_t* mobj;
+
+ // remove all the current thinkers
+ currentthinker = thinkercap.next;
+ while (currentthinker != &thinkercap)
+ {
+ next = currentthinker->next;
+
+ if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
+ P_RemoveMobj ((mobj_t *)currentthinker);
+ else
+ Z_Free (currentthinker);
+
+ currentthinker = next;
+ }
+ P_InitThinkers ();
+
+ // read in saved thinkers
+ while (1)
+ {
+ tclass = saveg_read8();
+ switch (tclass)
+ {
+ case tc_end:
+ return; // end of list
+
+ case tc_mobj:
+ saveg_read_pad();
+ mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
+ saveg_read_mobj_t(mobj);
+
+ // haleyjd 09/29/10: Strife sets the targets of non-allied creatures
+ // who had a non-NULL target at save time to players[0].mo so that
+ // they won't fall back asleep.
+ //
+ // BUG: As the player may not have been spawned yet, we could be
+ // setting monsters' targets to the mobj which was spawned by
+ // P_SetupLevel and then removed just above. Due to a subtle glitch
+ // in the DOOM engine whereby all things removed in this function
+ // are leaked until the next time P_SetupLevel is called, this is a
+ // safe operation - the call to P_InitThinkers above stops any of
+ // the objects removed, including the player's previous body, from
+ // being passed to Z_Free. One glitch relying on another!
+
+ if(mobj->target != NULL && (mobj->flags & MF_ALLY) != MF_ALLY)
+ mobj->target = players[0].mo;
+ else
+ mobj->target = NULL;
+
+ // WARNING! Strife does not seem to set tracer! I am leaving it be
+ // for now because so far no crashes have been observed, and failing
+ // to set this here will almost certainly crash Choco.
+ mobj->tracer = NULL;
+ P_SetThingPosition (mobj);
+ mobj->info = &mobjinfo[mobj->type];
+ // [STRIFE]: doesn't set these
+ //mobj->floorz = mobj->subsector->sector->floorheight;
+ //mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+ mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
+ P_AddThinker (&mobj->thinker);
+ break;
+
+ default:
+ I_Error ("Unknown tclass %i in savegame",tclass);
+ }
+ }
+}
+
+
+//
+// P_ArchiveSpecials
+//
+enum
+{
+ tc_ceiling,
+ tc_door,
+ tc_floor,
+ tc_plat,
+ tc_flash,
+ tc_strobe,
+ tc_glow,
+ tc_slidingdoor, // [STRIFE]
+ tc_endspecials
+
+} specials_e;
+
+
+
+//
+// Things to handle:
+//
+// T_MoveCeiling, (ceiling_t: sector_t * swizzle), - active list
+// T_VerticalDoor, (vldoor_t: sector_t * swizzle),
+// T_SlidingDoor, (slidedoor_t: sector_t *, line_t * x 2 swizzle) [STRIFE]
+// 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
+//
+void P_ArchiveSpecials (void)
+{
+ thinker_t* th;
+ int i;
+
+ // save off the current thinkers
+ for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
+ {
+ if (th->function.acv == (actionf_v)NULL)
+ {
+ for (i = 0; i < MAXCEILINGS;i++)
+ if (activeceilings[i] == (ceiling_t *)th)
+ break;
+
+ if (i<MAXCEILINGS)
+ {
+ saveg_write8(tc_ceiling);
+ saveg_write_pad();
+ saveg_write_ceiling_t((ceiling_t *) th);
+ }
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
+ {
+ saveg_write8(tc_ceiling);
+ saveg_write_pad();
+ saveg_write_ceiling_t((ceiling_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_VerticalDoor)
+ {
+ saveg_write8(tc_door);
+ saveg_write_pad();
+ saveg_write_vldoor_t((vldoor_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_SlidingDoor)
+ {
+ saveg_write8(tc_slidingdoor);
+ saveg_write_pad();
+ saveg_write_slidedoor_t((slidedoor_t *)th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_MoveFloor)
+ {
+ saveg_write8(tc_floor);
+ saveg_write_pad();
+ saveg_write_floormove_t((floormove_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_PlatRaise)
+ {
+ saveg_write8(tc_plat);
+ saveg_write_pad();
+ saveg_write_plat_t((plat_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_LightFlash)
+ {
+ saveg_write8(tc_flash);
+ saveg_write_pad();
+ saveg_write_lightflash_t((lightflash_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_StrobeFlash)
+ {
+ saveg_write8(tc_strobe);
+ saveg_write_pad();
+ saveg_write_strobe_t((strobe_t *) th);
+ continue;
+ }
+
+ if (th->function.acp1 == (actionf_p1)T_Glow)
+ {
+ saveg_write8(tc_glow);
+ saveg_write_pad();
+ saveg_write_glow_t((glow_t *) th);
+ continue;
+ }
+ }
+
+ // add a terminating marker
+ saveg_write8(tc_endspecials);
+}
+
+
+//
+// P_UnArchiveSpecials
+//
+void P_UnArchiveSpecials (void)
+{
+ byte tclass;
+ ceiling_t* ceiling;
+ vldoor_t* door;
+ slidedoor_t* slidedoor; // haleyjd [STRIFE]
+ floormove_t* floor;
+ plat_t* plat;
+ lightflash_t* flash;
+ strobe_t* strobe;
+ glow_t* glow;
+
+
+ // read in saved thinkers
+ while (1)
+ {
+ tclass = saveg_read8();
+
+ switch (tclass)
+ {
+ case tc_endspecials:
+ return; // end of list
+
+ case tc_ceiling:
+ saveg_read_pad();
+ ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVEL, NULL);
+ saveg_read_ceiling_t(ceiling);
+ ceiling->sector->specialdata = ceiling;
+
+ if (ceiling->thinker.function.acp1)
+ ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
+
+ P_AddThinker (&ceiling->thinker);
+ P_AddActiveCeiling(ceiling);
+ break;
+
+ case tc_door:
+ saveg_read_pad();
+ door = Z_Malloc (sizeof(*door), PU_LEVEL, NULL);
+ saveg_read_vldoor_t(door);
+ door->sector->specialdata = door;
+ door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
+ P_AddThinker (&door->thinker);
+ break;
+
+ case tc_slidingdoor:
+ // haleyjd 09/29/10: [STRIFE] New thinker type for sliding doors
+ saveg_read_pad();
+ slidedoor = Z_Malloc(sizeof(*slidedoor), PU_LEVEL, NULL);
+ saveg_read_slidedoor_t(slidedoor);
+ slidedoor->frontsector->specialdata = slidedoor;
+ slidedoor->thinker.function.acp1 = (actionf_p1)T_SlidingDoor;
+ P_AddThinker(&slidedoor->thinker);
+ break;
+
+ case tc_floor:
+ saveg_read_pad();
+ floor = Z_Malloc (sizeof(*floor), PU_LEVEL, NULL);
+ saveg_read_floormove_t(floor);
+ floor->sector->specialdata = floor;
+ floor->thinker.function.acp1 = (actionf_p1)T_MoveFloor;
+ P_AddThinker (&floor->thinker);
+ break;
+
+ case tc_plat:
+ saveg_read_pad();
+ plat = Z_Malloc (sizeof(*plat), PU_LEVEL, NULL);
+ saveg_read_plat_t(plat);
+ plat->sector->specialdata = plat;
+
+ if (plat->thinker.function.acp1)
+ plat->thinker.function.acp1 = (actionf_p1)T_PlatRaise;
+
+ P_AddThinker (&plat->thinker);
+ P_AddActivePlat(plat);
+ break;
+
+ case tc_flash:
+ saveg_read_pad();
+ flash = Z_Malloc (sizeof(*flash), PU_LEVEL, NULL);
+ saveg_read_lightflash_t(flash);
+ flash->thinker.function.acp1 = (actionf_p1)T_LightFlash;
+ P_AddThinker (&flash->thinker);
+ break;
+
+ case tc_strobe:
+ saveg_read_pad();
+ strobe = Z_Malloc (sizeof(*strobe), PU_LEVEL, NULL);
+ saveg_read_strobe_t(strobe);
+ strobe->thinker.function.acp1 = (actionf_p1)T_StrobeFlash;
+ P_AddThinker (&strobe->thinker);
+ break;
+
+ case tc_glow:
+ saveg_read_pad();
+ glow = Z_Malloc (sizeof(*glow), PU_LEVEL, NULL);
+ saveg_read_glow_t(glow);
+ glow->thinker.function.acp1 = (actionf_p1)T_Glow;
+ P_AddThinker (&glow->thinker);
+ break;
+
+ default:
+ I_Error ("P_UnarchiveSpecials:Unknown tclass %i "
+ "in savegame",tclass);
+ }
+ }
+}
+
diff --git a/src/strife/p_saveg.h b/src/strife/p_saveg.h
new file mode 100644
index 00000000..c0cfc666
--- /dev/null
+++ b/src/strife/p_saveg.h
@@ -0,0 +1,70 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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__
+
+#include <stdio.h>
+
+// maximum size of a savegame description
+
+#define SAVESTRINGSIZE 24
+
+// temporary filename to use while saving.
+
+char *P_TempSaveGameFile(void);
+
+// filename to use for a savegame slot
+
+char *P_SaveGameFile(int slot);
+
+// Savegame file header read/write functions
+
+boolean P_ReadSaveGameHeader(void);
+void P_WriteSaveGameHeader(char *description);
+
+// Savegame end-of-file read/write functions
+
+boolean P_ReadSaveGameEOF(void);
+void P_WriteSaveGameEOF(void);
+
+// Persistent storage/archiving.
+// These are the load / save game routines.
+void P_ArchivePlayers (void);
+void P_UnArchivePlayers (boolean userload);
+void P_ArchiveWorld (void);
+void P_UnArchiveWorld (void);
+void P_ArchiveThinkers (void);
+void P_UnArchiveThinkers (void);
+void P_ArchiveSpecials (void);
+void P_UnArchiveSpecials (void);
+
+extern FILE *save_stream;
+extern boolean savegame_error;
+
+
+#endif
diff --git a/src/strife/p_setup.c b/src/strife/p_setup.c
new file mode 100644
index 00000000..694d0185
--- /dev/null
+++ b/src/strife/p_setup.c
@@ -0,0 +1,865 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 "z_zone.h"
+
+#include "deh_main.h"
+#include "i_swap.h"
+#include "m_argv.h"
+#include "m_bbox.h"
+
+#include "g_game.h"
+
+#include "i_system.h"
+#include "w_wad.h"
+
+#include "doomdef.h"
+#include "p_local.h"
+
+#include "s_sound.h"
+
+#include "doomstat.h"
+
+
+void P_SpawnMapThing (mapthing_t* mthing);
+
+
+//
+// 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;
+
+static int totallines;
+
+// 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;
+int bmapheight; // size in mapblocks
+short* blockmap; // int for larger maps
+// offsets in blockmap are from here
+short* blockmaplump;
+// origin of block map
+fixed_t bmaporgx;
+fixed_t bmaporgy;
+// for thing chains
+mobj_t** blocklinks;
+
+
+// REJECT
+// For fast sight rejection.
+// Speeds up enemy AI by skipping detailed
+// LineOf Sight calculation.
+// Without special effect, this could be
+// used as a PVS lookup as well.
+//
+byte* rejectmatrix;
+
+
+// Maintain single and multi player starting spots.
+#define MAX_DEATHMATCH_STARTS 10
+
+mapthing_t deathmatchstarts[MAX_DEATHMATCH_STARTS];
+mapthing_t* deathmatch_p;
+mapthing_t playerstarts[MAXPLAYERS];
+
+// haleyjd 08/24/10: [STRIFE] rift spots for player spawning
+mapthing_t riftSpots[MAXRIFTSPOTS];
+
+
+
+
+//
+// P_LoadVertexes
+//
+void P_LoadVertexes (int lump)
+{
+ byte* data;
+ int i;
+ mapvertex_t* ml;
+ vertex_t* li;
+
+ // 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, PU_STATIC);
+
+ ml = (mapvertex_t *)data;
+ li = vertexes;
+
+ // Copy and convert vertex coordinates,
+ // internal representation as fixed.
+ for (i=0 ; i<numvertexes ; i++, li++, ml++)
+ {
+ li->x = SHORT(ml->x)<<FRACBITS;
+ li->y = SHORT(ml->y)<<FRACBITS;
+ }
+
+ // Free buffer memory.
+ W_ReleaseLumpNum(lump);
+}
+
+
+
+//
+// P_LoadSegs
+//
+void P_LoadSegs (int lump)
+{
+ byte* data;
+ int i;
+ mapseg_t* ml;
+ seg_t* li;
+ line_t* ldef;
+ int linedef;
+ int side;
+ int sidenum;
+
+ numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
+ segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0);
+ memset (segs, 0, numsegs*sizeof(seg_t));
+ data = W_CacheLumpNum (lump,PU_STATIC);
+
+ ml = (mapseg_t *)data;
+ li = segs;
+ for (i=0 ; i<numsegs ; i++, li++, ml++)
+ {
+ li->v1 = &vertexes[SHORT(ml->v1)];
+ li->v2 = &vertexes[SHORT(ml->v2)];
+
+ 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;
+
+ if (ldef-> flags & ML_TWOSIDED)
+ {
+ sidenum = ldef->sidenum[side ^ 1];
+
+ // If the sidenum is out of range, this may be a "glass hack"
+ // impassible window. Point at side #0 (this may not be
+ // the correct Vanilla behavior; however, it seems to work for
+ // OTTAWAU.WAD, which is the one place I've seen this trick
+ // used).
+
+ if (sidenum < 0 || sidenum >= numsides)
+ {
+ sidenum = 0;
+ }
+
+ li->backsector = sides[sidenum].sector;
+ }
+ else
+ {
+ li->backsector = 0;
+ }
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// P_LoadSubsectors
+//
+void P_LoadSubsectors (int lump)
+{
+ byte* data;
+ int i;
+ mapsubsector_t* ms;
+ subsector_t* ss;
+
+ numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
+ subsectors = Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0);
+ data = W_CacheLumpNum (lump,PU_STATIC);
+
+ ms = (mapsubsector_t *)data;
+ memset (subsectors,0, numsubsectors*sizeof(subsector_t));
+ ss = subsectors;
+
+ for (i=0 ; i<numsubsectors ; i++, ss++, ms++)
+ {
+ ss->numlines = SHORT(ms->numsegs);
+ ss->firstline = SHORT(ms->firstseg);
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+
+//
+// P_LoadSectors
+//
+void P_LoadSectors (int lump)
+{
+ byte* data;
+ int i;
+ mapsector_t* ms;
+ sector_t* ss;
+
+ numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
+ sectors = Z_Malloc (numsectors*sizeof(sector_t),PU_LEVEL,0);
+ memset (sectors, 0, numsectors*sizeof(sector_t));
+ data = W_CacheLumpNum (lump,PU_STATIC);
+
+ ms = (mapsector_t *)data;
+ ss = sectors;
+ for (i=0 ; i<numsectors ; i++, ss++, ms++)
+ {
+ 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->tag = SHORT(ms->tag);
+ ss->thinglist = NULL;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// P_LoadNodes
+//
+void P_LoadNodes (int lump)
+{
+ byte* data;
+ int i;
+ int j;
+ int k;
+ mapnode_t* mn;
+ node_t* no;
+
+ numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
+ nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);
+ data = W_CacheLumpNum (lump,PU_STATIC);
+
+ mn = (mapnode_t *)data;
+ no = nodes;
+
+ for (i=0 ; i<numnodes ; i++, no++, mn++)
+ {
+ 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++)
+ {
+ no->children[j] = SHORT(mn->children[j]);
+ for (k=0 ; k<4 ; k++)
+ no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
+ }
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// P_LoadThings
+//
+// haleyjd 08/24/10: [STRIFE]:
+// * Added code to record rift spots
+void P_LoadThings (int lump)
+{
+ byte *data;
+ int i;
+ mapthing_t *mt;
+ mapthing_t spawnthing;
+ int numthings;
+ boolean spawn;
+
+ data = W_CacheLumpNum (lump,PU_STATIC);
+ numthings = W_LumpLength (lump) / sizeof(mapthing_t);
+
+ mt = (mapthing_t *)data;
+ for (i=0 ; i<numthings ; i++, mt++)
+ {
+ spawn = true;
+
+ // Do not spawn cool, new monsters if !commercial
+ // STRIFE-TODO: replace with isregistered stuff
+ /*
+ if (gamemode != commercial)
+ {
+ switch (SHORT(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
+ spawn = false;
+ break;
+ }
+ }
+ if (spawn == false)
+ break;
+ */
+
+ // Do spawn all other stuff.
+ spawnthing.x = SHORT(mt->x);
+ spawnthing.y = SHORT(mt->y);
+ spawnthing.angle = SHORT(mt->angle);
+ spawnthing.type = SHORT(mt->type);
+ spawnthing.options = SHORT(mt->options);
+
+ // haleyjd 08/24/2010: Special Strife checks
+ if(spawnthing.type >= 118 && spawnthing.type < 128)
+ {
+ // initialize riftSpots
+ int riftSpotNum = spawnthing.type - 118;
+ riftSpots[riftSpotNum] = spawnthing;
+ riftSpots[riftSpotNum].type = 1;
+ }
+ else if(spawnthing.type >= 9001 && spawnthing.type < 9011)
+ {
+ // STRIFE-TODO: mystery array of 90xx objects
+ }
+ else
+ P_SpawnMapThing(&spawnthing);
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// P_LoadLineDefs
+// Also counts secret lines for intermissions.
+//
+void P_LoadLineDefs (int lump)
+{
+ byte* data;
+ int i;
+ maplinedef_t* mld;
+ line_t* ld;
+ vertex_t* v1;
+ vertex_t* v2;
+
+ numlines = W_LumpLength (lump) / sizeof(maplinedef_t);
+ lines = Z_Malloc (numlines*sizeof(line_t),PU_LEVEL,0);
+ memset (lines, 0, numlines*sizeof(line_t));
+ data = W_CacheLumpNum (lump,PU_STATIC);
+
+ mld = (maplinedef_t *)data;
+ ld = lines;
+ for (i=0 ; i<numlines ; i++, mld++, ld++)
+ {
+ 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;
+
+ if (!ld->dx)
+ ld->slopetype = ST_VERTICAL;
+ else if (!ld->dy)
+ ld->slopetype = ST_HORIZONTAL;
+ else
+ {
+ if (FixedDiv (ld->dy , ld->dx) > 0)
+ ld->slopetype = ST_POSITIVE;
+ else
+ ld->slopetype = 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]);
+
+ if (ld->sidenum[0] != -1)
+ ld->frontsector = sides[ld->sidenum[0]].sector;
+ else
+ ld->frontsector = 0;
+
+ if (ld->sidenum[1] != -1)
+ ld->backsector = sides[ld->sidenum[1]].sector;
+ else
+ ld->backsector = 0;
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// P_LoadSideDefs
+//
+void P_LoadSideDefs (int lump)
+{
+ byte* data;
+ int i;
+ mapsidedef_t* msd;
+ side_t* sd;
+
+ numsides = W_LumpLength (lump) / sizeof(mapsidedef_t);
+ sides = Z_Malloc (numsides*sizeof(side_t),PU_LEVEL,0);
+ memset (sides, 0, numsides*sizeof(side_t));
+ data = W_CacheLumpNum (lump,PU_STATIC);
+
+ msd = (mapsidedef_t *)data;
+ sd = sides;
+ for (i=0 ; i<numsides ; i++, msd++, sd++)
+ {
+ sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
+ sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
+ sd->toptexture = R_TextureNumForName(msd->toptexture);
+ sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
+ sd->midtexture = R_TextureNumForName(msd->midtexture);
+ sd->sector = &sectors[SHORT(msd->sector)];
+ }
+
+ W_ReleaseLumpNum(lump);
+}
+
+
+//
+// P_LoadBlockMap
+//
+void P_LoadBlockMap (int lump)
+{
+ int i;
+ int count;
+ int lumplen;
+
+ lumplen = W_LumpLength(lump);
+ count = lumplen / 2;
+
+ blockmaplump = Z_Malloc(lumplen, PU_LEVEL, NULL);
+ W_ReadLump(lump, blockmaplump);
+ blockmap = blockmaplump + 4;
+
+ // Swap all short integers to native byte ordering.
+
+ for (i=0; i<count; i++)
+ {
+ blockmaplump[i] = SHORT(blockmaplump[i]);
+ }
+
+ // Read the header
+
+ bmaporgx = blockmaplump[0]<<FRACBITS;
+ bmaporgy = blockmaplump[1]<<FRACBITS;
+ bmapwidth = blockmaplump[2];
+ bmapheight = blockmaplump[3];
+
+ // Clear out mobj chains
+
+ count = sizeof(*blocklinks) * bmapwidth * bmapheight;
+ blocklinks = Z_Malloc(count, PU_LEVEL, 0);
+ memset(blocklinks, 0, count);
+}
+
+
+
+//
+// P_GroupLines
+// Builds sector line lists and subsector sector numbers.
+// Finds block bounding boxes for sectors.
+//
+void P_GroupLines (void)
+{
+ line_t** linebuffer;
+ int i;
+ int j;
+ line_t* li;
+ sector_t* sector;
+ subsector_t* ss;
+ seg_t* seg;
+ fixed_t bbox[4];
+ int block;
+
+ // look up sector number for each subsector
+ ss = subsectors;
+ for (i=0 ; i<numsubsectors ; i++, ss++)
+ {
+ seg = &segs[ss->firstline];
+ ss->sector = seg->sidedef->sector;
+ }
+
+ // count number of lines in each sector
+ li = lines;
+ totallines = 0;
+ for (i=0 ; i<numlines ; i++, li++)
+ {
+ totallines++;
+ li->frontsector->linecount++;
+
+ if (li->backsector && li->backsector != li->frontsector)
+ {
+ li->backsector->linecount++;
+ totallines++;
+ }
+ }
+
+ // build line tables for each sector
+ linebuffer = Z_Malloc (totallines*sizeof(line_t *), PU_LEVEL, 0);
+
+ for (i=0; i<numsectors; ++i)
+ {
+ // Assign the line buffer for this sector
+
+ sectors[i].lines = linebuffer;
+ linebuffer += sectors[i].linecount;
+
+ // Reset linecount to zero so in the next stage we can count
+ // lines into the list.
+
+ sectors[i].linecount = 0;
+ }
+
+ // Assign lines to sectors
+
+ for (i=0; i<numlines; ++i)
+ {
+ li = &lines[i];
+
+ if (li->frontsector != NULL)
+ {
+ sector = li->frontsector;
+
+ sector->lines[sector->linecount] = li;
+ ++sector->linecount;
+ }
+
+ if (li->backsector != NULL && li->frontsector != li->backsector)
+ {
+ sector = li->backsector;
+
+ sector->lines[sector->linecount] = li;
+ ++sector->linecount;
+ }
+ }
+
+ // Generate bounding boxes for sectors
+
+ sector = sectors;
+ for (i=0 ; i<numsectors ; i++, sector++)
+ {
+ M_ClearBox (bbox);
+
+ for (j=0 ; j<sector->linecount; j++)
+ {
+ li = sector->lines[j];
+
+ M_AddToBox (bbox, li->v1->x, li->v1->y);
+ M_AddToBox (bbox, li->v2->x, li->v2->y);
+ }
+
+ // 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;
+ }
+
+}
+
+// Pad the REJECT lump with extra data when the lump is too small,
+// to simulate a REJECT buffer overflow in Vanilla Doom.
+
+static void PadRejectArray(byte *array, unsigned int len)
+{
+ unsigned int i;
+ unsigned int byte_num;
+ byte *dest;
+ unsigned int padvalue;
+
+ // Values to pad the REJECT array with:
+
+ unsigned int rejectpad[4] =
+ {
+ ((totallines * 4 + 3) & ~3) + 24, // Size
+ 0, // Part of z_zone block header
+ 50, // PU_LEVEL
+ 0x1d4a11 // DOOM_CONST_ZONEID
+ };
+
+ // Copy values from rejectpad into the destination array.
+
+ dest = array;
+
+ for (i=0; i<len && i<sizeof(rejectpad); ++i)
+ {
+ byte_num = i % 4;
+ *dest = (rejectpad[i / 4] >> (byte_num * 8)) & 0xff;
+ ++dest;
+ }
+
+ // We only have a limited pad size. Print a warning if the
+ // REJECT lump is too small.
+
+ if (len > sizeof(rejectpad))
+ {
+ fprintf(stderr, "PadRejectArray: REJECT lump too short to pad! (%i > %i)\n",
+ len, sizeof(rejectpad));
+
+ // Pad remaining space with 0 (or 0xff, if specified on command line).
+
+ if (M_CheckParm("-reject_pad_with_ff"))
+ {
+ padvalue = 0xff;
+ }
+ else
+ {
+ padvalue = 0xf00;
+ }
+
+ memset(array + sizeof(rejectpad), padvalue, len - sizeof(rejectpad));
+ }
+}
+
+static void P_LoadReject(int lumpnum)
+{
+ int minlength;
+ int lumplen;
+
+ // Calculate the size that the REJECT lump *should* be.
+
+ minlength = (numsectors * numsectors + 7) / 8;
+
+ // If the lump meets the minimum length, it can be loaded directly.
+ // Otherwise, we need to allocate a buffer of the correct size
+ // and pad it with appropriate data.
+
+ lumplen = W_LumpLength(lumpnum);
+
+ if (lumplen >= minlength)
+ {
+ rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL);
+ }
+ else
+ {
+ rejectmatrix = Z_Malloc(minlength, PU_LEVEL, &rejectmatrix);
+ W_ReadLump(lumpnum, rejectmatrix);
+
+ PadRejectArray(rejectmatrix + lumplen, minlength - lumplen);
+ }
+}
+
+//
+// P_SetupLevel
+//
+void
+P_SetupLevel
+( int map,
+ int playermask,
+ skill_t skill)
+{
+ int i;
+ char lumpname[9];
+ int lumpnum;
+
+ // haleyjd 20110205 [STRIFE]: removed totalitems and wminfo
+ totalkills = totalsecret = 0;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ // haleyjd 20100830: [STRIFE] Removed secretcount, itemcount
+ // 20110205: [STRIFE] Initialize players.allegiance
+ players[i].allegiance = i;
+ players[i].killcount = 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 ();
+
+
+#if 0 // UNUSED
+ if (debugfile)
+ {
+ Z_FreeTags (PU_LEVEL, INT_MAX);
+ Z_FileDumpHeap (debugfile);
+ }
+ else
+#endif
+ Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
+
+
+ // UNUSED W_Profile ();
+ P_InitThinkers ();
+
+ // [STRIFE] Removed ExMy map support
+ if (map<10)
+ DEH_snprintf(lumpname, 9, "map0%i", map);
+ else
+ DEH_snprintf(lumpname, 9, "map%i", map);
+
+ lumpnum = W_GetNumForName (lumpname);
+
+ leveltime = 0;
+
+ // note: most of this ordering is important
+ P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
+ P_LoadVertexes (lumpnum+ML_VERTEXES);
+ P_LoadSectors (lumpnum+ML_SECTORS);
+ P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
+
+ P_LoadLineDefs (lumpnum+ML_LINEDEFS);
+ P_LoadSubsectors (lumpnum+ML_SSECTORS);
+ P_LoadNodes (lumpnum+ML_NODES);
+ P_LoadSegs (lumpnum+ML_SEGS);
+
+ P_GroupLines ();
+ P_LoadReject (lumpnum+ML_REJECT);
+
+ //bodyqueslot = 0; [STRIFE] unused
+ deathmatch_p = deathmatchstarts;
+ 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);
+ }
+
+ }
+
+ // clear special respawning que
+ iquehead = iquetail = 0;
+
+ // set up world state
+ P_SpawnSpecials ();
+
+ // build subsector connect matrix
+ // UNUSED P_ConnectSubsectors ();
+
+ // preload graphics
+ if (precache)
+ R_PrecacheLevel ();
+
+ //printf ("free memory: 0x%x\n", Z_FreeMemory());
+}
+
+
+
+//
+// P_Init
+//
+void P_Init (void)
+{
+ P_InitSwitchList();
+ P_InitPicAnims();
+ P_InitTerrainTypes(); // villsa [STRIFE]
+ R_InitSprites(sprnames);
+}
+
+
+
diff --git a/src/strife/p_setup.h b/src/strife/p_setup.h
new file mode 100644
index 00000000..1befd7ae
--- /dev/null
+++ b/src/strife/p_setup.h
@@ -0,0 +1,45 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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__
+
+
+
+
+// NOT called by W_Ticker. Fixme.
+// [STRIFE] Removed episode parameter
+void
+P_SetupLevel
+( int map,
+ int playermask,
+ skill_t skill);
+
+// Called by startup code.
+void P_Init (void);
+
+#endif
diff --git a/src/strife/p_sight.c b/src/strife/p_sight.c
new file mode 100644
index 00000000..e0b2ad3c
--- /dev/null
+++ b/src/strife/p_sight.c
@@ -0,0 +1,368 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 "doomdef.h"
+
+#include "i_system.h"
+#include "p_local.h"
+
+// State.
+#include "r_state.h"
+
+//
+// P_CheckSight
+//
+fixed_t sightzstart; // eye z of looker
+fixed_t topslope;
+fixed_t bottomslope; // slopes to top and bottom of target
+
+divline_t strace; // from t1 to t2
+fixed_t t2x;
+fixed_t t2y;
+
+int sightcounts[2];
+
+
+//
+// P_DivlineSide
+// Returns side 0 (front), 1 (back), or 2 (on).
+//
+// [STRIFE] Verified unmodified
+//
+int
+P_DivlineSide
+( fixed_t x,
+ fixed_t y,
+ divline_t* node )
+{
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t left;
+ fixed_t right;
+
+ if (!node->dx)
+ {
+ if (x==node->x)
+ return 2;
+
+ if (x <= node->x)
+ return node->dy > 0;
+
+ return node->dy < 0;
+ }
+
+ if (!node->dy)
+ {
+ if (x==node->y)
+ return 2;
+
+ if (y <= node->y)
+ return node->dx < 0;
+
+ return node->dx > 0;
+ }
+
+ dx = (x - node->x);
+ dy = (y - node->y);
+
+ left = (node->dy>>FRACBITS) * (dx>>FRACBITS);
+ right = (dy>>FRACBITS) * (node->dx>>FRACBITS);
+
+ if (right < left)
+ return 0; // front side
+
+ if (left == right)
+ return 2;
+ return 1; // back side
+}
+
+
+//
+// P_InterceptVector2
+// Returns the fractional intercept point
+// along the first divline.
+// This is only called by the addthings and addlines traversers.
+//
+// [STRIFE] Verified unmodified
+//
+fixed_t
+P_InterceptVector2
+( divline_t* v2,
+ divline_t* v1 )
+{
+ fixed_t frac;
+ fixed_t num;
+ fixed_t den;
+
+ den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy);
+
+ if (den == 0)
+ return 0;
+ // I_Error ("P_InterceptVector: parallel");
+
+ num = FixedMul ( (v1->x - v2->x)>>8 ,v1->dy) +
+ FixedMul ( (v2->y - v1->y)>>8 , v1->dx);
+ frac = FixedDiv (num , den);
+
+ return frac;
+}
+
+//
+// P_CrossSubsector
+// Returns true
+// if strace crosses the given subsector successfully.
+//
+// [STRIFE] Verified unmodified
+//
+boolean P_CrossSubsector (int num)
+{
+ seg_t* seg;
+ line_t* line;
+ int s1;
+ int s2;
+ int count;
+ subsector_t* sub;
+ sector_t* front;
+ sector_t* back;
+ fixed_t opentop;
+ fixed_t openbottom;
+ divline_t divl;
+ vertex_t* v1;
+ vertex_t* v2;
+ fixed_t frac;
+ fixed_t slope;
+
+#ifdef RANGECHECK
+ if (num>=numsubsectors)
+ I_Error ("P_CrossSubsector: ss %i with numss = %i",
+ num,
+ numsubsectors);
+#endif
+
+ sub = &subsectors[num];
+
+ // check lines
+ count = sub->numlines;
+ seg = &segs[sub->firstline];
+
+ for ( ; count ; seg++, count--)
+ {
+ line = seg->linedef;
+
+ // allready checked other side?
+ if (line->validcount == validcount)
+ continue;
+
+ line->validcount = validcount;
+
+ v1 = line->v1;
+ v2 = line->v2;
+ s1 = P_DivlineSide (v1->x, v1->y, &strace);
+ s2 = P_DivlineSide (v2->x, v2->y, &strace);
+
+ // line isn't crossed?
+ if (s1 == s2)
+ continue;
+
+ divl.x = v1->x;
+ divl.y = v1->y;
+ divl.dx = v2->x - v1->x;
+ divl.dy = v2->y - v1->y;
+ s1 = P_DivlineSide (strace.x, strace.y, &divl);
+ s2 = P_DivlineSide (t2x, t2y, &divl);
+
+ // line isn't crossed?
+ if (s1 == s2)
+ continue;
+
+ // Backsector may be NULL if this is an "impassible
+ // glass" hack line.
+
+ if (line->backsector == NULL)
+ {
+ return false;
+ }
+
+ // stop because it is not two sided anyway
+ // might do this after updating validcount?
+ if ( !(line->flags & ML_TWOSIDED) )
+ return false;
+
+ // crosses a two sided line
+ front = seg->frontsector;
+ back = seg->backsector;
+
+ // no wall to block sight with?
+ if (front->floorheight == back->floorheight
+ && front->ceilingheight == back->ceilingheight)
+ continue;
+
+ // possible occluder
+ // because of ceiling height differences
+ if (front->ceilingheight < back->ceilingheight)
+ opentop = front->ceilingheight;
+ else
+ opentop = back->ceilingheight;
+
+ // because of ceiling height differences
+ if (front->floorheight > back->floorheight)
+ openbottom = front->floorheight;
+ else
+ openbottom = back->floorheight;
+
+ // quick test for totally closed doors
+ if (openbottom >= opentop)
+ return false; // stop
+
+ frac = P_InterceptVector2 (&strace, &divl);
+
+ if (front->floorheight != back->floorheight)
+ {
+ slope = FixedDiv (openbottom - sightzstart , frac);
+ if (slope > bottomslope)
+ bottomslope = slope;
+ }
+
+ if (front->ceilingheight != back->ceilingheight)
+ {
+ slope = FixedDiv (opentop - sightzstart , frac);
+ if (slope < topslope)
+ topslope = slope;
+ }
+
+ if (topslope <= bottomslope)
+ return false; // stop
+ }
+ // passed the subsector ok
+ return true;
+}
+
+
+
+//
+// P_CrossBSPNode
+// Returns true
+// if strace crosses the given node successfully.
+//
+// [STRIFE] Verified unmodified
+//
+boolean P_CrossBSPNode (int bspnum)
+{
+ node_t* bsp;
+ int side;
+
+ if (bspnum & NF_SUBSECTOR)
+ {
+ if (bspnum == -1)
+ return P_CrossSubsector (0);
+ else
+ return P_CrossSubsector (bspnum&(~NF_SUBSECTOR));
+ }
+
+ bsp = &nodes[bspnum];
+
+ // decide which side the start point is on
+ side = P_DivlineSide (strace.x, strace.y, (divline_t *)bsp);
+ if (side == 2)
+ side = 0; // an "on" should cross both sides
+
+ // cross the starting side
+ if (!P_CrossBSPNode (bsp->children[side]) )
+ return false;
+
+ // the partition plane is crossed here
+ if (side == P_DivlineSide (t2x, t2y,(divline_t *)bsp))
+ {
+ // the line doesn't touch the other side
+ return true;
+ }
+
+ // cross the ending side
+ return P_CrossBSPNode (bsp->children[side^1]);
+}
+
+
+//
+// P_CheckSight
+// Returns true
+// if a straight line between t1 and t2 is unobstructed.
+// Uses REJECT.
+//
+// [STRIFE] Verified unmodified
+//
+boolean
+P_CheckSight
+( mobj_t* t1,
+ mobj_t* t2 )
+{
+ int s1;
+ int s2;
+ int pnum;
+ int bytenum;
+ int bitnum;
+
+ // First check for trivial rejection.
+
+ // Determine subsector entries in REJECT table.
+ s1 = (t1->subsector->sector - sectors);
+ s2 = (t2->subsector->sector - sectors);
+ pnum = s1*numsectors + s2;
+ bytenum = pnum>>3;
+ bitnum = 1 << (pnum&7);
+
+ // Check in REJECT table.
+ if (rejectmatrix[bytenum]&bitnum)
+ {
+ sightcounts[0]++;
+
+ // can't possibly be connected
+ return false;
+ }
+
+ // An unobstructed LOS is possible.
+ // Now look from eyes of t1 to any part of t2.
+ sightcounts[1]++;
+
+ validcount++;
+
+ sightzstart = t1->z + t1->height - (t1->height>>2);
+ topslope = (t2->z+t2->height) - sightzstart;
+ bottomslope = (t2->z) - sightzstart;
+
+ strace.x = t1->x;
+ strace.y = t1->y;
+ t2x = t2->x;
+ t2y = t2->y;
+ strace.dx = t2->x - t1->x;
+ strace.dy = t2->y - t1->y;
+
+ // the head node is the last node output
+ return P_CrossBSPNode (numnodes-1);
+}
+
+
diff --git a/src/strife/p_spec.c b/src/strife/p_spec.c
new file mode 100644
index 00000000..10a778bb
--- /dev/null
+++ b/src/strife/p_spec.c
@@ -0,0 +1,1996 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// Implements special effects:
+// Texture animation, height or lighting changes
+// according to adjacent sectors, respective
+// utility functions, etc.
+// Line Tag handling. Line and Sector triggers.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "deh_main.h"
+#include "i_system.h"
+#include "z_zone.h"
+#include "m_argv.h"
+#include "m_misc.h"
+#include "m_random.h"
+#include "w_wad.h"
+
+#include "r_local.h"
+#include "p_local.h"
+
+#include "g_game.h"
+
+#include "s_sound.h"
+
+// State.
+#include "r_state.h"
+
+// Data.
+#include "sounds.h"
+
+// [STRIFE]
+#include "hu_stuff.h"
+#include "p_dialog.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
+//
+typedef struct
+{
+ int istexture; // if false, it is a flat
+ char endname[9];
+ char startname[9];
+ int speed;
+} animdef_t;
+
+
+// haleyjd 08/30/10: [STRIFE] MAXANIMS raised from 32 to 40
+#define MAXANIMS 40
+
+//
+// P_InitPicAnims
+//
+
+// Floor/ceiling animation sequences,
+// defined by first and last frame,
+// i.e. the flat (64x64 tile) name to
+// be used.
+// The full animation sequence is given
+// using all the flats between the start
+// and end entry, in the order found in
+// the WAD file.
+//
+// haleyjd 08/29/10: [STRIFE] Changed animdefs.
+//
+animdef_t animdefs[] =
+{
+ { false, "F_SCANR8", "F_SCANR5", 4},
+ { false, "F_WATR03", "F_WATR01", 8},
+ { false, "F_PWATR3", "F_PWATR1", 11},
+ { false, "F_SCANR4", "F_SCANR1", 4},
+ { true, "SCAN08", "SCAN05", 4},
+ { true, "SWTRMG03", "SWTRMG01", 4},
+ { true, "SCAN04", "SCAN01", 4},
+ { true, "COMP04", "COMP01", 4},
+ { true, "COMP08", "COMP05", 6},
+ { true, "COMP12", "COMP09", 11},
+ { true, "COMP16", "COMP13", 12},
+ { true, "COMP20", "COMP17", 12},
+ { true, "COMP24", "COMP21", 12},
+ { true, "COMP28", "COMP25", 12},
+ { true, "COMP32", "COMP29", 12},
+ { true, "COMP37", "COMP33", 12},
+ { true, "COMP41", "COMP38", 12},
+ { true, "COMP49", "COMP42", 10},
+ { true, "BRKGRY16", "BRKGRY13", 10},
+ { true, "BRNSCN04", "BRNSCN01", 10},
+ { true, "CONCRT12", "CONCRT09", 11},
+ { true, "CONCRT25", "CONCRT22", 11},
+ { true, "WALPMP02", "WALPMP01", 16},
+ { true, "WALTEK17", "WALTEK16", 8},
+ { true, "FORCE04", "FORCE01", 4},
+ { true, "FORCE08", "FORCE05", 4},
+ { true, "FAN02", "FAN01", 4},
+ { false, "F_VWATR3", "P_VWATR1", 4},
+ { false, "F_HWATR3", "F_HWATR1", 4},
+ { false, "F_TELE2", "F_TELE1", 4},
+ { false, "F_FAN2", "F_FAN1", 4},
+ { false, "F_CONVY2", "F_CONVY1", 4},
+ { false, "F_RDALN4", "F_RDALN1", 4},
+ { -1, "", "", 0},
+};
+
+anim_t anims[MAXANIMS];
+anim_t* lastanim;
+
+//
+// Animating line specials
+//
+// haleyjd 08/29/10: [STRIFE] MAXLINEANIMS raised from 64 to 96
+#define MAXLINEANIMS 96
+
+extern short numlinespecials;
+extern line_t* linespeciallist[MAXLINEANIMS];
+
+
+
+void P_InitPicAnims (void)
+{
+ int i;
+
+
+ // Init animation
+ lastanim = anims;
+ for (i=0 ; animdefs[i].istexture != -1 ; i++)
+ {
+ char *startname, *endname;
+
+ startname = DEH_String(animdefs[i].startname);
+ endname = DEH_String(animdefs[i].endname);
+
+ if (animdefs[i].istexture)
+ {
+ // different episode ?
+ if (R_CheckTextureNumForName(startname) == -1)
+ continue;
+
+ lastanim->picnum = R_TextureNumForName(endname);
+ lastanim->basepic = R_TextureNumForName(startname);
+ }
+ else
+ {
+ if (W_CheckNumForName(startname) == -1)
+ continue;
+
+ lastanim->picnum = R_FlatNumForName(endname);
+ lastanim->basepic = R_FlatNumForName(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",
+ startname, endname);
+
+ lastanim->speed = animdefs[i].speed;
+ lastanim++;
+ }
+
+}
+
+// villsa [STRIFE] terrain type definitions
+typedef struct
+{
+ char* flat;
+ int type;
+ int num;
+} terraintype_t;
+
+terraintype_t terraintypes[] =
+{
+ { "F_WATR03", FLOOR_WATER, -1 },
+ { "F_WATR02", FLOOR_WATER, -1 },
+ { "F_WATR01", FLOOR_WATER, -1 },
+ { "F_VWATR3", FLOOR_WATER, -1 },
+ { "F_VWATR2", FLOOR_WATER, -1 },
+ { "P_VWATR1", FLOOR_WATER, -1 },
+ { "F_HWATR3", FLOOR_WATER, -1 },
+ { "F_HWATR2", FLOOR_WATER, -1 },
+ { "F_HWATR1", FLOOR_WATER, -1 },
+ { "F_PWATR3", FLOOR_SLIME, -1 },
+ { "F_PWATR2", FLOOR_SLIME, -1 },
+ { "F_PWATR1", FLOOR_SLIME, -1 },
+ { "END", FLOOR_END, -1 },
+};
+
+//
+// P_GetTerrainType
+// villsa [STRIFE] new function
+//
+
+terraintype_e P_GetTerrainType(mobj_t* mobj)
+{
+ int i = 0;
+ subsector_t* ss = mobj->subsector;
+
+ if(mobj->z <= ss->sector->floorheight &&
+ terraintypes[0].type != FLOOR_END)
+ {
+ while(ss->sector->floorpic != terraintypes[i].num)
+ {
+ if(terraintypes[i+1].type == FLOOR_END)
+ return FLOOR_SOLID;
+
+ i++;
+ }
+
+ return terraintypes[i].type;
+ }
+
+ return FLOOR_SOLID;
+}
+
+//
+// P_InitTerrainTypes
+// villsa [STRIFE] new function
+// Initialize terrain types
+//
+
+void P_InitTerrainTypes(void)
+{
+ int i = 0;
+
+ if(terraintypes[0].type != FLOOR_END)
+ {
+ while(terraintypes[i].type != FLOOR_END)
+ {
+ terraintypes[i].num = R_FlatNumForName(terraintypes[i].flat);
+ i++;
+ }
+ }
+}
+
+
+
+//
+// UTILITIES
+//
+
+
+
+//
+// getSide()
+// Will return a side_t*
+// given the number of the current sector,
+// the line number, and the side (0/1) that you want.
+//
+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.
+//
+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.
+//
+int
+twoSided
+( int sector,
+ int line )
+{
+ return (sectors[sector].lines[line])->flags & ML_TWOSIDED;
+}
+
+
+
+
+//
+// getNextSector()
+// Return sector_t * of sector next to current.
+// NULL if not two-sided line
+//
+sector_t*
+getNextSector
+( line_t* line,
+ sector_t* sec )
+{
+ if (!(line->flags & ML_TWOSIDED))
+ return NULL;
+
+ if (line->frontsector == sec)
+ return line->backsector;
+
+ return line->frontsector;
+}
+
+
+
+//
+// P_FindLowestFloorSurrounding()
+// FIND LOWEST FLOOR HEIGHT IN 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()
+// FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
+//
+fixed_t P_FindHighestFloorSurrounding(sector_t *sec)
+{
+ int i;
+ line_t* check;
+ sector_t* other;
+ fixed_t floor = -500*FRACUNIT;
+
+ 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
+// FIND NEXT HIGHEST FLOOR IN SURROUNDING SECTORS
+// Note: this should be doable w/o a fixed array.
+
+// Thanks to entryway for the Vanilla overflow emulation.
+
+// 20 adjoining sectors max!
+#define MAX_ADJOINING_SECTORS 20
+
+fixed_t
+P_FindNextHighestFloor
+( sector_t* sec,
+ int currentheight )
+{
+ int i;
+ int h;
+ int min;
+ line_t* check;
+ sector_t* other;
+ fixed_t height = currentheight;
+ fixed_t heightlist[MAX_ADJOINING_SECTORS + 2];
+
+ for (i=0, h=0; i < sec->linecount; i++)
+ {
+ check = sec->lines[i];
+ other = getNextSector(check,sec);
+
+ if (!other)
+ continue;
+
+ if (other->floorheight > height)
+ {
+ // Emulation of memory (stack) overflow
+ if (h == MAX_ADJOINING_SECTORS + 1)
+ {
+ height = other->floorheight;
+ }
+ else if (h == MAX_ADJOINING_SECTORS + 2)
+ {
+ // Fatal overflow: game crashes at 22 textures
+ I_Error("Sector with more than 22 adjoining sectors. "
+ "Vanilla will crash here");
+ }
+
+ heightlist[h++] = other->floorheight;
+ }
+ }
+
+ // Find lowest height in list
+ if (!h)
+ {
+ return currentheight;
+ }
+
+ min = heightlist[0];
+
+ // Range checking?
+ for (i = 1; i < h; i++)
+ {
+ if (heightlist[i] < min)
+ {
+ min = heightlist[i];
+ }
+ }
+
+ return min;
+}
+
+//
+// FIND LOWEST CEILING IN THE SURROUNDING SECTORS
+//
+fixed_t
+P_FindLowestCeilingSurrounding(sector_t* sec)
+{
+ int i;
+ line_t* check;
+ sector_t* other;
+ fixed_t height = INT_MAX;
+
+ 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;
+}
+
+
+//
+// FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
+//
+fixed_t P_FindHighestCeilingSurrounding(sector_t* sec)
+{
+ int i;
+ line_t* check;
+ sector_t* other;
+ fixed_t height = 0;
+
+ 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;
+}
+
+
+
+//
+// RETURN NEXT SECTOR # THAT LINE TAG REFERS TO
+//
+int
+P_FindSectorFromLineTag
+( line_t* line,
+ int start )
+{
+ int i;
+
+ for (i=start+1;i<numsectors;i++)
+ if (sectors[i].tag == line->tag)
+ return i;
+
+ return -1;
+}
+
+
+
+
+//
+// Find minimum light from an adjacent sector
+//
+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;
+}
+
+
+
+//
+// EVENTS
+// Events are operations triggered by using, crossing,
+// or shooting special lines, or by timed thinkers.
+//
+
+// [STRIFE]
+static char crosslinestr[90];
+
+//
+// P_CrossSpecialLine - TRIGGER
+// Called every time a thing origin is about
+// to cross a line with a non 0 special.
+//
+void
+P_CrossSpecialLine
+( int linenum,
+ int side,
+ mobj_t* thing )
+{
+ line_t* line;
+ side_t* sidedef; // [STRIFE]
+ int flag; // [STRIFE]
+ int ok;
+
+ line = &lines[linenum];
+
+ // haleyjd 09/21/10: corpses and missiles cannot activate any cross-over
+ // line types, *except* 182 (which is for the sake of missiles).
+ if((thing->flags & (MF_MISSILE|MF_CORPSE)) && line->special != 182)
+ return;
+
+ // Triggers that other things can activate
+ if (!thing->player)
+ {
+ // Things that should NOT trigger specials...
+ // villsa [STRIFE] unused
+ // haleyjd: removed dead switch. Strife only excludes missiles and
+ // corpses, which is handled above.
+
+ ok = 0;
+
+ // [STRIFE] Added several line types. Removed none.
+ switch(line->special)
+ {
+ case 97: // TELEPORT RETRIGGER
+ case 185: // haleyjd: [STRIFE] Silent Teleport (used for Converter)
+ case 195: // haleyjd: [STRIFE] Silent Teleport and Change Zombie
+ case 231: // haleyjd: [STRIFE] WR Teleport (Silent at Source)
+ case 125: // TELEPORT MONSTERONLY TRIGGER
+ case 126: // TELEPORT MONSTERONLY RETRIGGER
+ case 182: // haleyjd: [STRIFE] Break glass - it's a W1 type too!
+ case 10: // PLAT DOWN-WAIT-UP-STAY TRIGGER
+ case 39: // TELEPORT TRIGGER
+ case 88: // PLAT DOWN-WAIT-UP-STAY RETRIGGER
+ case 4: // RAISE DOOR
+ ok = 1;
+ break;
+ }
+ if (!ok)
+ return;
+ }
+
+
+ // Note: could use some const's here.
+ switch (line->special)
+ {
+ //
+ // TRIGGERS.
+ // All from here to RETRIGGERS.
+ //
+ case 230:
+ // haleyjd 09/21/10: [STRIFE] W1 Open Door if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1;
+
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+ // fall-through:
+ case 2:
+ // Open Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,open);
+ line->special = 0;
+ break;
+
+ case 227:
+ // haleyjd 09/21/10: [STRIFE] W1 Close Door if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1;
+
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+ // fall-through:
+ case 3:
+ // Close Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,close);
+ line->special = 0;
+ break;
+
+ case 4:
+ // Raise Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,normal);
+ line->special = 0;
+ break;
+
+ case 5:
+ // Raise Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloor);
+ line->special = 0;
+ break;
+
+ case 6:
+ // Fast Ceiling Crush & Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,fastCrushAndRaise);
+ line->special = 0;
+ break;
+
+ case 8:
+ // Build Stairs - [STRIFE] Verified unmodified.
+ EV_BuildStairs(line,build8);
+ line->special = 0;
+ break;
+
+ case 10:
+ // PlatDownWaitUp - [STRIFE] Verified unmodified.
+ EV_DoPlat(line,downWaitUpStay,0);
+ line->special = 0;
+ break;
+
+ case 12:
+ // Light Turn On - brightest near - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,0);
+ line->special = 0;
+ break;
+
+ case 13:
+ // Light Turn On 255 - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,255);
+ line->special = 0;
+ break;
+
+ case 16:
+ // Close Door 30 - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,close30ThenOpen);
+ line->special = 0;
+ break;
+
+ case 17:
+ // Start Light Strobing - [STRIFE] Verified unmodified.
+ EV_StartLightStrobing(line);
+ line->special = 0;
+ break;
+
+ case 19:
+ // Lower Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,lowerFloor);
+ line->special = 0;
+ break;
+
+ case 22:
+ // villsa [STRIFE] Verified unmodified.
+ // Raise floor to nearest height and change texture
+ EV_DoPlat(line,raiseToNearestAndChange,0);
+ line->special = 0;
+ break;
+
+ case 25:
+ // Ceiling Crush and Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,crushAndRaise);
+ line->special = 0;
+ break;
+
+ case 30:
+ // Raise floor to shortest texture height - [STRIFE] Verified unmodified.
+ // on either side of lines.
+ EV_DoFloor(line,raiseToTexture);
+ line->special = 0;
+ break;
+
+ case 35:
+ // Lights Very Dark - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,35);
+ line->special = 0;
+ break;
+
+ case 36:
+ // Lower Floor (TURBO) - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,turboLower);
+ line->special = 0;
+ break;
+
+ case 37:
+ // LowerAndChange - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,lowerAndChange);
+ line->special = 0;
+ break;
+
+ case 193:
+ // haleyjd 09/21/10: [STRIFE] W1 Floor Lower to Lowest if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1; // note is fixed_t
+
+ // must have the questflag indicated in the line's y offset
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+ // fall-through:
+ case 38:
+ // Lower Floor To Lowest - [STRIFE] Verified unmodified.
+ EV_DoFloor( line, lowerFloorToLowest );
+ line->special = 0;
+ break;
+
+ case 39:
+ // TELEPORT! - [STRIFE] Verified unmodified (except for 0 flags param)
+ EV_Teleport( line, side, thing, TF_NORMAL );
+ line->special = 0;
+ break;
+
+ /*case 40:
+ // RaiseCeilingLowerFloor
+ EV_DoCeiling( line, raiseToHighest );
+ EV_DoFloor( line, lowerFloorToLowest );
+ line->special = 0;
+ break;*/
+
+ case 44:
+ // Ceiling Crush - [STRIFE] Verified unmodified.
+ EV_DoCeiling( line, lowerAndCrush );
+ line->special = 0;
+ break;
+
+ case 52:
+ // EXIT! - haleyjd 09/21/10: [STRIFE] Exit to level tag/100
+ G_ExitLevel (line->tag / 100);
+ break;
+
+ case 53:
+ // Perpetual Platform Raise - [STRIFE] Verified unmodified.
+ EV_DoPlat(line,perpetualRaise,0);
+ line->special = 0;
+ break;
+
+ case 54:
+ // Platform Stop - [STRIFE] Verified unmodified.
+ EV_StopPlat(line);
+ line->special = 0;
+ break;
+
+ case 56:
+ // Raise Floor Crush - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorCrush);
+ line->special = 0;
+ break;
+
+ case 57:
+ // Ceiling Crush Stop - [STRIFE] Verified unmodified.
+ EV_CeilingCrushStop(line);
+ line->special = 0;
+ break;
+
+ case 58:
+ // [STRIFE] raiseFloor24 was modified into raiseFloor64
+ // Raise Floor 64
+ EV_DoFloor(line,raiseFloor64);
+ line->special = 0;
+ break;
+
+ case 59:
+ // Raise Floor 24 And Change - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloor24AndChange);
+ line->special = 0;
+ break;
+
+ case 104:
+ // Turn lights off in sector(tag) - [STRIFE] Verified unmodified.
+ EV_TurnTagLightsOff(line);
+ line->special = 0;
+ break;
+
+ case 108:
+ // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeRaise);
+ line->special = 0;
+ break;
+
+ case 109:
+ // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeOpen);
+ line->special = 0;
+ break;
+
+ case 100:
+ // Build Stairs Turbo 16 - [STRIFE] Verified unmodified.
+ EV_BuildStairs(line,turbo16);
+ line->special = 0;
+ break;
+
+ case 197:
+ // haleyjd 09/21/10: [STRIFE] Blazing Door Close if Has Sigil B
+ if(thing->player->sigiltype <= 0)
+ break;
+ // fall-through:
+ case 110:
+ // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeClose);
+ line->special = 0;
+ break;
+
+ case 119:
+ // Raise floor to nearest surr. floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorToNearest);
+ line->special = 0;
+ break;
+
+ case 121:
+ // villsa [STRIFE] Verified unmodified.
+ // Blazing PlatDownWaitUpStay
+ EV_DoPlat(line,blazeDWUS,0);
+ line->special = 0;
+ break;
+
+ case 124:
+ // haleyjd 09/21/10: [STRIFE] W1 Start Finale
+ // Altered from G_SecretExitLevel.
+ G_StartFinale();
+ break;
+
+ case 125:
+ // TELEPORT MonsterONLY - [STRIFE] Verified unmodified
+ // (except for 0 flags parameter)
+ if (!thing->player)
+ {
+ EV_Teleport( line, side, thing, TF_NORMAL );
+ line->special = 0;
+ }
+ break;
+
+ case 130:
+ // Raise Floor Turbo - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorTurbo);
+ line->special = 0;
+ break;
+
+ case 141:
+ // Silent Ceiling Crush & Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,silentCrushAndRaise);
+ line->special = 0;
+ break;
+
+ case 174:
+ // villsa [STRIFE] Split Open
+ EV_DoDoor(line, splitOpen);
+ line->special = 0;
+ break;
+
+ case 183:
+ // villsa [STRIFE] Split Raise Nearest
+ EV_DoDoor(line, splitRaiseNearest);
+ line->special = 0;
+ break;
+
+ case 178:
+ // haleyjd 09/24/10: [STRIFE] W1 Build Stairs Down 16
+ EV_BuildStairs(line, buildDown16);
+ line->special = 0;
+ break;
+
+ case 179:
+ // haleyjd 09/25/10: [STRIFE] W1 Ceiling Lower to Floor
+ EV_DoCeiling(line, lowerToFloor);
+ line->special = 0;
+ break;
+
+ case 182:
+ // haleyjd 09/21/10: [STRIFE] Break Glass
+ // 182 is a unique linetype in that it is both a G1 and a W1 linetype,
+ // but only missiles may activate it as a W1 type.
+ if(thing->flags & MF_MISSILE)
+ P_ChangeSwitchTexture(line, 1); // why 1? it will be cleared anyway.
+ break;
+
+ case 187:
+ // haleyjd 09/21/10: [STRIFE] W1 Clear Force Fields if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1; // note is fixed_t
+
+ // must have the questflag indicated in the line's y offset
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+
+ // Do it!
+ EV_ClearForceFields(line);
+ line->special = 0;
+ break;
+
+ case 188:
+ // haleyjd 09/21/10: [STRIFE] W1 Open Door if Quest 16 (Gate Mechanism
+ // Destroyed)
+ if(!(thing->player->questflags & QF_QUEST16))
+ break;
+ EV_DoDoor(line, open);
+ line->special = 0;
+ break;
+
+ case 196:
+ // haleyjd 09/26/10: [STRIFE] W1 Floor Lower to Lowest if Sigil Type > 0
+ if(thing->player->sigiltype > 0)
+ {
+ EV_DoFloor(line, lowerFloorToLowest);
+ line->special = 0;
+ }
+ break;
+
+ case 200:
+ // haleyjd 09/21/10: [STRIFE] W1 Open Door if Sigil Owned
+ if(!(thing->player->weaponowned[wp_sigil]))
+ break;
+ EV_DoDoor(line, open);
+ line->special = 0;
+ break;
+
+ case 201:
+ // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective (First Side Only)
+ if(side == 1)
+ break;
+ // fall-through:
+ case 202:
+ // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective (Tag = VOC/LOG #)
+ // must be consoleplayer
+ if(thing->player != &players[consoleplayer])
+ break;
+
+ // must have comm unit
+ if(!(thing->player->powers[pw_communicator]))
+ break;
+
+ // load voice
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "voc%i", line->tag);
+ I_StartVoice(crosslinestr);
+
+ // load objective
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "log%i", line->tag);
+ GiveObjective(crosslinestr, 0);
+
+ // Put up a message
+ thing->player->message = DEH_String("Incoming Message...");
+ line->special = 0;
+ break;
+
+ case 210:
+ // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective if Flamethrower????
+ // I don't think this is actually used anywhere o_O
+ // must be player 1...
+ if(thing->player != &players[0])
+ break;
+
+ // must have comm unit
+ if(!(thing->player->powers[pw_communicator]))
+ break;
+
+ // must have... the flamethrower?!
+ if(!(thing->player->weaponowned[wp_flame]))
+ break;
+
+ // load voice
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "voc%i", line->tag);
+ I_StartVoice(crosslinestr);
+
+ // load objective
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "log%i", line->tag);
+ GiveObjective(crosslinestr, 0);
+
+ // Put up a message
+ thing->player->message = DEH_String("Incoming Message from BlackBird...");
+ line->special = 0;
+ break;
+
+ case 212:
+ // haleyjd 09/25/10: [STRIFE] W1 Floor Lower to Lowest if Have Flamethrower
+ if(thing->player->weaponowned[wp_flame])
+ {
+ EV_DoFloor(line, lowerFloorToLowest);
+ line->special = 0;
+ }
+ break;
+
+ case 215:
+ // haleyjd 09/21/10: [STRIFE] W1 Voiced Objective if Quest (Tag/100, Tag%100)
+ // must be player 1...
+ if(thing->player != &players[0])
+ break;
+
+ // must have comm unit
+ if(!(thing->player->powers[pw_communicator]))
+ break;
+
+ if(line->tag != 0)
+ {
+ // test for questflag
+ if(!(thing->player->questflags & (1 << (line->tag % 100 - 1))))
+ break;
+ }
+
+ // start voice
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "voc%i", line->tag/100);
+ I_StartVoice(crosslinestr);
+
+ // give objective
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr), "log%i", line->tag/100);
+ GiveObjective(crosslinestr, 0);
+
+ // Put up a message
+ thing->player->message = DEH_String("Incoming Message from BlackBird...");
+ line->special = 0;
+ break;
+
+ case 204:
+ // haleyjd 09/21/10: [STRIFE] W1 Change Music (unused!)
+ if(thing->player != &players[0])
+ break;
+ S_ChangeMusic(line->tag, 1);
+ line->special = 0;
+ break;
+
+ case 228:
+ // haleyjd 09/21/10: [STRIFE] W1 Entity Voice?
+ if(!(thing->player->questflags & QF_QUEST24)) // Not killed Macil???
+ break; // STRIFE-TODO: verify...
+
+ if(!(thing->player->questflags & QF_QUEST28)) // ????? STRIFE-TODO
+ I_StartVoice(DEH_String("voc128"));
+ else
+ I_StartVoice(DEH_String("voc130"));
+
+ line->special = 0;
+ break;
+
+ //
+ // RETRIGGERS. All from here till end.
+ //
+ case 72:
+ // Ceiling Crush - [STRIFE] Verified unmodified.
+ EV_DoCeiling( line, lowerAndCrush );
+ break;
+
+ case 73:
+ // Ceiling Crush and Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,crushAndRaise);
+ break;
+
+ case 74:
+ // Ceiling Crush Stop - [STRIFE] Verified unmodified.
+ EV_CeilingCrushStop(line);
+ break;
+
+ case 75:
+ // Close Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,close);
+ break;
+
+ case 76:
+ // Close Door 30 - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,close30ThenOpen);
+ break;
+
+ case 77:
+ // Fast Ceiling Crush & Raise - [STRIFE] Verified unmodified.
+ EV_DoCeiling(line,fastCrushAndRaise);
+ break;
+
+ case 79:
+ // Lights Very Dark - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,35);
+ break;
+
+ case 80:
+ // Light Turn On - brightest near - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,0);
+ break;
+
+ case 81:
+ // Light Turn On 255 - [STRIFE] Verified unmodified.
+ EV_LightTurnOn(line,255);
+ break;
+
+ case 82:
+ // Lower Floor To Lowest - [STRIFE] Verified unmodified.
+ EV_DoFloor( line, lowerFloorToLowest );
+ break;
+
+ case 83:
+ // Lower Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,lowerFloor);
+ break;
+
+ case 84:
+ // LowerAndChange - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,lowerAndChange);
+ break;
+
+ case 86:
+ // Open Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,open);
+ break;
+
+ case 87:
+ // Perpetual Platform Raise - [STRIFE] Verified unmodified.
+ EV_DoPlat(line,perpetualRaise,0);
+ break;
+
+ case 88:
+ // PlatDownWaitUp - [STRIFE] Verified unmodified.
+ EV_DoPlat(line,downWaitUpStay,0);
+ break;
+
+ case 89:
+ // Platform Stop - [STRIFE] Verified unmodified.
+ EV_StopPlat(line);
+ break;
+
+ case 216:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Door if Quest
+ sidedef = &sides[line->sidenum[0]];
+ flag = (sidedef->rowoffset >> FRACBITS) - 1; // note is fixed_t.
+
+ if(!(thing->player->questflags & (1 << flag)))
+ break;
+ // fall-through:
+ case 90:
+ // Raise Door - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,normal);
+ break;
+
+ case 91:
+ // Raise Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloor);
+ break;
+
+ case 92:
+ // [STRIFE] raiseFloor24 changed to raiseFloor64
+ // Raise Floor 64
+ EV_DoFloor(line,raiseFloor64);
+ break;
+
+ case 93:
+ // Raise Floor 24 And Change - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloor24AndChange);
+ break;
+
+ case 94:
+ // Raise Floor Crush - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorCrush);
+ break;
+
+ case 95:
+ // villsa [STRIFE] Verified unmodified.
+ // Raise floor to nearest height
+ // and change texture.
+ EV_DoPlat(line,raiseToNearestAndChange,0);
+ break;
+
+ case 96:
+ // Raise floor to shortest texture height - [STRIFE] Verified unmodified.
+ // on either side of lines.
+ EV_DoFloor(line,raiseToTexture);
+ break;
+
+ case 97:
+ // TELEPORT! - [STRIFE] Verified unmodified (except for 0 flags param)
+ EV_Teleport( line, side, thing, TF_NORMAL );
+ break;
+
+ case 98:
+ // Lower Floor (TURBO) - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,turboLower);
+ break;
+
+ case 105:
+ // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeRaise);
+ break;
+
+ case 106:
+ // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeOpen);
+ break;
+
+ case 107:
+ // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified.
+ EV_DoDoor (line,blazeClose);
+ break;
+
+ case 120:
+ // villsa [STRIFE] Verified unmodified.
+ // Blazing PlatDownWaitUpStay.
+ EV_DoPlat(line,blazeDWUS,0);
+ break;
+
+ case 126:
+ // TELEPORT MonsterONLY. - [STRIFE] Verified unmodified (except for 0 flags param)
+ if (!thing->player)
+ EV_Teleport( line, side, thing, TF_NORMAL );
+ break;
+
+ case 128:
+ // Raise To Nearest Floor - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorToNearest);
+ break;
+
+ case 129:
+ // Raise Floor Turbo - [STRIFE] Verified unmodified.
+ EV_DoFloor(line,raiseFloorTurbo);
+ break;
+
+ case 186:
+ // haleyjd [STRIFE] Exit Level to Spot, First Side Only
+ if(side == 1)
+ break;
+ // fall-through:
+ case 145:
+ // haleyjd [STRIFE] Exit Level to Spot
+ thing->momx = thing->momy = thing->momz = 0;
+ {
+ int map = line->tag / 100;
+ int spot = line->tag % 100;
+
+ if(thing->player->weaponowned[wp_sigil])
+ {
+ if(map == 3)
+ map = 30;
+ else if(map == 7)
+ map = 10;
+ }
+
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr),
+ "Entering%s",
+ DEH_String(mapnames[map - 1]) + 8);
+ thing->player->message = crosslinestr;
+
+ if(netgame && deathmatch)
+ {
+ if(levelTimer && levelTimeCount != 0)
+ {
+ DEH_snprintf(crosslinestr, sizeof(crosslinestr),
+ "%d min left",
+ (levelTimeCount/TICRATE)/60);
+ break;
+ }
+
+ // raise switch from floor
+ EV_DoFloor(line, raiseFloor64);
+ }
+ else
+ {
+ // normal single-player exit
+
+ // BUG: Here is the opening for a flaming player to cross past
+ // the exit line and hit a deathmatch switch ;) It's not so much
+ // that this is incorrect, as that they forgot to add such a
+ // check to the other kind of exit lines too ;)
+ if(thing->player->health <= 0)
+ break;
+
+ G_RiftExitLevel(map, spot, thing->angle);
+ }
+ }
+ break;
+
+ case 175:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if < 16 Above Floor
+ if(thing->z < thing->floorz + 16 * FRACUNIT)
+ P_NoiseAlert(thing->player->mo, thing->player->mo);
+ break;
+
+ case 198:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if No Guard Uniform
+ if(P_PlayerHasItem(thing->player, MT_QUEST_GUARD_UNIFORM))
+ break;
+ // fall-through:
+ case 150:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm
+ P_NoiseAlert(thing->player->mo, thing->player->mo);
+ break;
+
+ case 208:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if Have Flamethrower
+ // O_o - this is definitely unused. Was an entire flamethrower quest
+ // cut out of the game before release?
+ if(thing->player->weaponowned[wp_flame])
+ P_NoiseAlert(thing->player->mo, thing->player->mo);
+ break;
+
+ case 206:
+ // haleyjd 09/21/10: [STRIFE] WR Raise Alarm if Have Chalice
+ // This *is* used, inside the Tavern in Tarnhill. Oddly there is also
+ // one just randomly placed outside the entrance to the Power Station.
+ if(P_PlayerHasItem(thing->player, MT_INV_CHALICE))
+ P_NoiseAlert(thing->player->mo, thing->player->mo);
+ break;
+
+ case 184:
+ // villsa [STRIFE] plat up wait down stay
+ if(EV_DoPlat(line, upWaitDownStay, 0))
+ P_ChangeSwitchTexture(line, 1); // In P_CrossSpecialLine? Copypasta error?
+ break;
+
+ case 185:
+ // haleyjd 09/21/10: [STRIFE] Silent Teleport (used for Converter)
+ EV_Teleport(line, side, thing, TF_FULLSILENCE);
+ break;
+
+ case 195:
+ // haleyjd 09/21/10: [STRIFE] Silent Teleport and Change Zombie
+ EV_Teleport(line, side, thing, TF_FULLSILENCE);
+ P_SetMobjState(thing, S_AGRD_00); // 419
+ break;
+
+ case 203:
+ // haleyjd 09/21/10: [STRIFE] WR Change Music
+ if(thing->player != &players[0])
+ break;
+ S_ChangeMusic(line->tag, 1);
+ break;
+
+ case 231:
+ // haleyjd 09/21/10: [STRIFE] WR Teleport (Silent at Source)
+ EV_Teleport(line, side, thing, TF_SRCSILENCE);
+ break;
+
+ // haleyjd 09/21/10: Moved one-time-use lines up above with the others.
+ }
+}
+
+
+
+//
+// P_ShootSpecialLine - IMPACT SPECIALS
+// Called when a thing shoots a special line.
+//
+void
+P_ShootSpecialLine
+( mobj_t* thing,
+ line_t* line )
+{
+ int ok;
+
+ // Impacts that other things can activate.
+ if (!thing->player)
+ {
+ ok = 0;
+ switch(line->special)
+ {
+ case 46: // OPEN DOOR IMPACT
+ case 182: // villsa [STRIFE] for windows
+ ok = 1;
+ break;
+ }
+ if (!ok)
+ return;
+ }
+
+ switch(line->special)
+ {
+ case 24:
+ // RAISE FLOOR - [STRIFE] Verified unmodified
+ EV_DoFloor(line,raiseFloor);
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 46:
+ // OPEN DOOR - [STRIFE] Verified unmodified.
+ EV_DoDoor(line,open);
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 47:
+ // villsa [STRIFE] Verified unmodified.
+ // RAISE FLOOR NEAR AND CHANGE
+ EV_DoPlat(line,raiseToNearestAndChange,0);
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 180:
+ // haleyjd 09/22/10: [STRIFE] G1 Raise Floor 512 & Change
+ EV_DoFloor(line, raiseFloor512AndChange);
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 182:
+ // villsa [STRIFE] G1 Break Glass
+ // haleyjd: note that 182 is also a W1 type in P_CrossSpecialLine, but
+ // can only be activated in that manner by an MF_MISSILE object.
+ P_ChangeSwitchTexture(line, 0);
+ break;
+ }
+}
+
+
+
+//
+// P_PlayerInSpecialSector
+// Called every tic frame
+// that the player origin is in a special sector
+//
+// [STRIFE] Modified for new sector types and changes to old ones.
+//
+void P_PlayerInSpecialSector (player_t* player)
+{
+ sector_t* sector;
+
+ sector = player->mo->subsector->sector;
+
+ // Falling, not all the way down yet?
+ if (player->mo->z != sector->floorheight)
+ return;
+
+ // Has hitten ground.
+ switch (sector->special)
+ {
+ case 5:
+ // HELLSLIME DAMAGE
+ // [STRIFE] +2 to nukagecount
+ if(!player->powers[pw_ironfeet])
+ player->nukagecount += 2;
+ break;
+
+ case 16:
+ // [STRIFE] +4 to nukagecount
+ if(!player->powers[pw_ironfeet])
+ player->nukagecount += 4;
+ break;
+
+ case 4:
+ case 7:
+ // [STRIFE] Immediate 5 damage every 31 tics
+ if(!player->powers[pw_ironfeet])
+ if(!(leveltime & 0x1f))
+ P_DamageMobj(player->mo, NULL, NULL, 5);
+ break;
+
+ case 9:
+ // SECRET SECTOR
+ //player->secretcount++; [STRIFE] Don't have a secret count.
+ sector->special = 0;
+ if(player - players == consoleplayer)
+ S_StartSound(NULL, sfx_yeah);
+ break;
+
+ case 11:
+ // EXIT SUPER DAMAGE! (for E1M8 finale)
+ player->cheats &= ~CF_GODMODE;
+
+ if (!(leveltime&0x1f))
+ P_DamageMobj (player->mo, NULL, NULL, 20);
+
+ if (player->health <= 10)
+ G_ExitLevel(0);
+ break;
+
+ case 15:
+ // haleyjd 08/30/10: [STRIFE] "Instant" Death sector
+ P_DamageMobj(player->mo, NULL, NULL, 999);
+ break;
+
+
+ case 18:
+ // haleyjd 08/30/10: [STRIFE] Water current
+ {
+ int tagval = sector->tag - 100;
+ fixed_t force;
+ angle_t angle;
+
+ if(player->cheats & CF_NOCLIP)
+ return;
+
+ force = (tagval % 10) << 12;
+ angle = (tagval / 10) << 29;
+
+ P_Thrust(player, angle, force);
+ }
+ break;
+
+ default:
+ I_Error ("P_PlayerInSpecialSector: "
+ "unknown special %i",
+ sector->special);
+ break;
+ };
+}
+
+
+
+
+//
+// P_UpdateSpecials
+// Animate planes, scroll walls, etc.
+//
+// [STRIFE] Modifications to support multiple scrolling line types.
+//
+boolean levelTimer;
+int levelTimeCount;
+
+void P_UpdateSpecials (void)
+{
+ anim_t* anim;
+ int pic;
+ int i;
+ line_t* line;
+
+
+ // LEVEL TIMER
+ if (levelTimer == true)
+ {
+ if(levelTimeCount) // [STRIFE] Does not allow to go negative
+ levelTimeCount--;
+
+ /*
+ // [STRIFE] Not done here. Exit lines check this manually instead.
+ if (!levelTimeCount)
+ G_ExitLevel(0);
+ */
+ }
+
+ // 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;
+ }
+ }
+
+
+ // ANIMATE LINE SPECIALS
+ for (i = 0; i < numlinespecials; i++)
+ {
+ line = linespeciallist[i];
+ switch(line->special)
+ {
+ case 48:
+ // EFFECT FIRSTCOL SCROLL +
+ sides[line->sidenum[0]].textureoffset += FRACUNIT;
+ break;
+
+ case 142:
+ // haleyjd 09/25/10 [STRIFE] Scroll Up Slow
+ sides[line->sidenum[0]].rowoffset += FRACUNIT;
+ break;
+
+ case 143:
+ // haleyjd 09/25/10 [STRIFE] Scroll Down Fast (3 Units/Tic)
+ sides[line->sidenum[0]].rowoffset -= 3*FRACUNIT;
+ break;
+
+ case 149:
+ // haleyjd 09/25/10 [STRIFE] Scroll Down Slow
+ sides[line->sidenum[0]].rowoffset -= FRACUNIT;
+ break;
+ }
+ }
+
+
+ // DO BUTTONS
+ 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(&buttonlist[i].soundorg,sfx_swtchn);
+ memset(&buttonlist[i],0,sizeof(button_t));
+ }
+ }
+}
+
+
+//
+// Donut overrun emulation
+//
+// Derived from the code from PrBoom+. Thanks go to Andrey Budko (entryway)
+// as usual :-)
+//
+
+#define DONUT_FLOORHEIGHT_DEFAULT 0x00000000
+#define DONUT_FLOORPIC_DEFAULT 0x16
+
+static void DonutOverrun(fixed_t *s3_floorheight, short *s3_floorpic,
+ line_t *line, sector_t *pillar_sector)
+{
+ static int first = 1;
+ static int tmp_s3_floorheight;
+ static int tmp_s3_floorpic;
+
+ extern int numflats;
+
+ if (first)
+ {
+ int p;
+
+ // This is the first time we have had an overrun.
+ first = 0;
+
+ // Default values
+ tmp_s3_floorheight = DONUT_FLOORHEIGHT_DEFAULT;
+ tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT;
+
+ //!
+ // @category compat
+ // @arg <x> <y>
+ //
+ // Use the specified magic values when emulating behavior caused
+ // by memory overruns from improperly constructed donuts.
+ // In Vanilla Doom this can differ depending on the operating
+ // system. The default (if this option is not specified) is to
+ // emulate the behavior when running under Windows 98.
+
+ p = M_CheckParmWithArgs("-donut", 2);
+
+ if (p > 0)
+ {
+ // Dump of needed memory: (fixed_t)0000:0000 and (short)0000:0008
+ //
+ // C:\>debug
+ // -d 0:0
+ //
+ // DOS 6.22:
+ // 0000:0000 (57 92 19 00) F4 06 70 00-(16 00)
+ // DOS 7.1:
+ // 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00)
+ // Win98:
+ // 0000:0000 (00 00 00 00) 65 04 70 00-(16 00)
+ // DOSBox under XP:
+ // 0000:0000 (00 00 00 F1) ?? ?? ?? 00-(07 00)
+
+ M_StrToInt(myargv[p + 1], &tmp_s3_floorheight);
+ M_StrToInt(myargv[p + 2], &tmp_s3_floorpic);
+
+ if (tmp_s3_floorpic >= numflats)
+ {
+ fprintf(stderr,
+ "DonutOverrun: The second parameter for \"-donut\" "
+ "switch should be greater than 0 and less than number "
+ "of flats (%d). Using default value (%d) instead. \n",
+ numflats, DONUT_FLOORPIC_DEFAULT);
+ tmp_s3_floorpic = DONUT_FLOORPIC_DEFAULT;
+ }
+ }
+ }
+
+ /*
+ fprintf(stderr,
+ "Linedef: %d; Sector: %d; "
+ "New floor height: %d; New floor pic: %d\n",
+ line->iLineID, pillar_sector->iSectorID,
+ tmp_s3_floorheight >> 16, tmp_s3_floorpic);
+ */
+
+ *s3_floorheight = (fixed_t) tmp_s3_floorheight;
+ *s3_floorpic = (short) tmp_s3_floorpic;
+}
+
+
+//
+// Special Stuff that can not be categorized
+//
+int EV_DoDonut(line_t* line)
+{
+ sector_t* s1;
+ sector_t* s2;
+ sector_t* s3;
+ int secnum;
+ int rtn;
+ int i;
+ floormove_t* floor;
+ fixed_t s3_floorheight;
+ short s3_floorpic;
+
+ secnum = -1;
+ rtn = 0;
+ while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
+ {
+ s1 = &sectors[secnum];
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (s1->specialdata)
+ continue;
+
+ rtn = 1;
+ s2 = getNextSector(s1->lines[0],s1);
+
+ // Vanilla Doom does not check if the linedef is one sided. The
+ // game does not crash, but reads invalid memory and causes the
+ // sector floor to move "down" to some unknown height.
+ // DOSbox prints a warning about an invalid memory access.
+ //
+ // I'm not sure exactly what invalid memory is being read. This
+ // isn't something that should be done, anyway.
+ // Just print a warning and return.
+
+ if (s2 == NULL)
+ {
+ fprintf(stderr,
+ "EV_DoDonut: linedef had no second sidedef! "
+ "Unexpected behavior may occur in Vanilla Doom. \n");
+ break;
+ }
+
+ for (i = 0; i < s2->linecount; i++)
+ {
+ s3 = s2->lines[i]->backsector;
+
+ if (s3 == s1)
+ continue;
+
+ if (s3 == NULL)
+ {
+ // e6y
+ // s3 is NULL, so
+ // s3->floorheight is an int at 0000:0000
+ // s3->floorpic is a short at 0000:0008
+ // Trying to emulate
+
+ fprintf(stderr,
+ "EV_DoDonut: WARNING: emulating buffer overrun due to "
+ "NULL back sector. "
+ "Unexpected behavior may occur in Vanilla Doom.\n");
+
+ DonutOverrun(&s3_floorheight, &s3_floorpic, line, s1);
+ }
+ else
+ {
+ s3_floorheight = s3->floorheight;
+ s3_floorpic = s3->floorpic;
+ }
+
+ // Spawn rising slime
+ floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
+ P_AddThinker (&floor->thinker);
+ s2->specialdata = floor;
+ floor->thinker.function.acp1 = (actionf_p1) 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
+ floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
+ P_AddThinker (&floor->thinker);
+ s1->specialdata = floor;
+ floor->thinker.function.acp1 = (actionf_p1) 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;
+}
+
+
+
+//
+// SPECIAL SPAWNING
+//
+
+//
+// P_SpawnSpecials
+// After the map has been loaded, scan for specials
+// that spawn thinkers
+//
+short numlinespecials;
+line_t* linespeciallist[MAXLINEANIMS];
+
+
+// Parses command line parameters.
+//
+// haleyjd 09/25/10: [STRIFE] Modifications for more scrolling line types and
+// for initialization of sliding door resources.
+//
+void P_SpawnSpecials (void)
+{
+ sector_t* sector;
+ int i;
+
+ // See if -TIMER was specified.
+
+ if (timelimit > 0 && deathmatch)
+ {
+ levelTimer = true;
+ levelTimeCount = timelimit * 60 * TICRATE;
+ }
+ else
+ {
+ levelTimer = false;
+ }
+
+ // Init special SECTORs - [STRIFE] Verified unmodified.
+ sector = sectors;
+ for (i=0 ; i<numsectors ; i++, sector++)
+ {
+ if (!sector->special)
+ continue;
+
+ switch (sector->special)
+ {
+ case 1:
+ // FLICKERING LIGHTS
+ 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 = 4;
+ break;
+
+ case 8:
+ // GLOWING LIGHT
+ P_SpawnGlowingLight(sector);
+ break;
+ case 9:
+ // SECRET SECTOR
+ totalsecret++;
+ 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:
+ P_SpawnFireFlicker(sector);
+ break;
+ }
+ }
+
+
+ // Init line EFFECTs
+ numlinespecials = 0;
+ for (i = 0;i < numlines; i++)
+ {
+ switch(lines[i].special)
+ {
+ case 48: // EFFECT FIRSTCOL SCROLL+
+ case 142:
+ case 143:
+ case 149:
+ linespeciallist[numlinespecials] = &lines[i];
+ numlinespecials++;
+ break;
+ }
+ }
+
+ // Init other misc stuff
+ for (i = 0;i < MAXCEILINGS;i++)
+ activeceilings[i] = NULL;
+
+ for (i = 0;i < MAXPLATS;i++)
+ activeplats[i] = NULL;
+
+ for (i = 0;i < MAXBUTTONS;i++)
+ memset(&buttonlist[i],0,sizeof(button_t));
+
+ // villsa [STRIFE]
+ P_InitSlidingDoorFrames();
+}
diff --git a/src/strife/p_spec.h b/src/strife/p_spec.h
new file mode 100644
index 00000000..7215c0b7
--- /dev/null
+++ b/src/strife/p_spec.h
@@ -0,0 +1,686 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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
+// Implements special effects:
+// Texture animation, height or lighting changes
+// according to adjacent sectors, respective
+// utility functions, etc.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __P_SPEC__
+#define __P_SPEC__
+
+
+//
+// End-level timer (-TIMER option)
+//
+extern boolean levelTimer;
+extern int levelTimeCount;
+
+
+// Define values for map objects
+#define MO_TELEPORTMAN 14
+
+
+// at game start
+void P_InitPicAnims (void);
+
+// villsa [STRIFE]
+typedef enum
+{
+ FLOOR_WATER = 0,
+ FLOOR_SLIME = 1,
+ FLOOR_SOLID = 2,
+ FLOOR_END = -1
+} terraintype_e;
+
+void P_InitTerrainTypes(void); // villsa [STRIFE]
+terraintype_e P_GetTerrainType(mobj_t* mobj); // villsa [STRIFE]
+
+// 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
+( int linenum,
+ int side,
+ mobj_t* thing );
+
+void P_PlayerInSpecialSector (player_t* player);
+
+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_FindLowestCeilingSurrounding(sector_t* sec);
+fixed_t P_FindHighestCeilingSurrounding(sector_t* sec);
+
+int
+P_FindSectorFromLineTag
+( line_t* line,
+ int start );
+
+int
+P_FindMinSurroundingLight
+( sector_t* sector,
+ int max );
+
+sector_t*
+getNextSector
+( line_t* line,
+ sector_t* sec );
+
+
+//
+// SPECIAL
+//
+int EV_DoDonut(line_t* line);
+boolean EV_ClearForceFields(line_t* line); // villsa [STRIFE]
+
+
+//
+// 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;
+
+
+#define GLOWSPEED 8
+#define STROBEBRIGHT 5
+#define FASTDARK 15
+#define SLOWDARK 35
+
+void P_SpawnFireFlicker (sector_t* sector);
+void T_LightFlash (lightflash_t* flash);
+void P_SpawnLightFlash (sector_t* sector);
+void T_StrobeFlash (strobe_t* flash);
+
+void
+P_SpawnStrobeFlash
+( sector_t* sector,
+ int fastOrSlow,
+ int inSync );
+
+void EV_StartLightStrobing(line_t* line);
+void EV_TurnTagLightsOff(line_t* line);
+
+void
+EV_LightTurnOn
+( line_t* line,
+ int bright );
+
+void T_Glow(glow_t* g);
+void P_SpawnGlowingLight(sector_t* sector);
+
+
+
+
+//
+// P_SWITCH
+//
+typedef struct
+{
+ char name1[9];
+ char name2[9];
+ short episode;
+ int sound; // villsa [STRIFE]
+
+} switchlist_t;
+
+
+typedef enum
+{
+ top,
+ middle,
+ bottom
+
+} bwhere_e;
+
+
+typedef struct
+{
+ line_t* line;
+ bwhere_e where;
+ int btexture;
+ int btimer;
+ degenmobj_t *soundorg;
+
+} button_t;
+
+
+
+
+ // max # of wall switches in a level
+#define MAXSWITCHES 80 // villsa [STRIFE] changed from 50 to 80
+
+ // 4 players, 4 buttons each at once, max.
+#define MAXBUTTONS 16
+
+ // 1 second, in ticks.
+#define BUTTONTIME 35
+
+extern button_t buttonlist[MAXBUTTONS];
+
+void
+P_ChangeSwitchTexture
+( line_t* line,
+ int useAgain );
+
+void P_InitSwitchList(void);
+
+
+//
+// P_PLATS
+//
+typedef enum
+{
+ up,
+ down,
+ waiting,
+ in_stasis
+
+} plat_e;
+
+
+
+typedef enum
+{
+ perpetualRaise,
+ downWaitUpStay,
+ slowDWUS, // villsa [STRIFE]
+ raiseAndChange,
+ raiseToNearestAndChange,
+ blazeDWUS,
+ upWaitDownStay // villsa [STRIFE]
+
+} plattype_e;
+
+
+
+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;
+
+} plat_t;
+
+
+
+#define PLATWAIT 3
+#define PLATSPEED FRACUNIT
+#define MAXPLATS 30
+
+
+extern plat_t* activeplats[MAXPLATS];
+
+void T_PlatRaise(plat_t* plat);
+
+int
+EV_DoPlat
+( line_t* line,
+ plattype_e type,
+ int amount );
+
+void P_AddActivePlat(plat_t* plat);
+void P_RemoveActivePlat(plat_t* plat);
+void EV_StopPlat(line_t* line);
+void P_ActivateInStasis(int tag);
+
+
+//
+// P_DOORS
+//
+typedef enum
+{
+ normal,
+ close30ThenOpen,
+ close,
+ open,
+ raiseIn5Mins,
+ blazeRaise,
+ blazeOpen,
+ blazeClose,
+ shopClose, // villsa [STRIFE]
+ splitRaiseNearest, // villsa [STRIFE]
+ splitOpen // villsa [STRIFE]
+
+} vldoor_e;
+
+
+
+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;
+
+ // villsa [STRIFE] new field - sound to play when opening
+ int opensound;
+
+ // villsa [STRIFE] new field - sound to play when closing
+ int closesound;
+
+} vldoor_t;
+
+
+
+#define VDOORSPEED FRACUNIT*2
+#define VDOORWAIT 150
+
+void
+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 );
+
+void T_VerticalDoor (vldoor_t* door);
+void P_SpawnDoorCloseIn30 (sector_t* sec);
+
+void
+P_SpawnDoorRaiseIn5Mins
+( sector_t* sec,
+ int secnum );
+
+
+
+// villsa [STRIFE] resurrected sliding doors
+//
+// Sliding doors...
+//
+typedef enum
+{
+ sd_opening,
+ sd_waiting,
+ sd_closing
+
+} sd_e;
+
+
+
+typedef enum
+{
+ sdt_openOnly,
+ sdt_closeOnly,
+ sdt_openAndClose
+
+} sdt_e;
+
+
+
+// villsa [STRIFE] Rogue added a second line_t in the struct
+// backsector is removed
+typedef struct
+{
+ thinker_t thinker;
+ sdt_e type;
+ line_t* line1;
+ line_t* line2;
+ int frame;
+ int whichDoorIndex;
+ int timer;
+ sector_t* frontsector;
+ sd_e status;
+
+} slidedoor_t;
+
+// villsa [STRIFE] no front/back frames
+typedef struct
+{
+ char frame1[9];
+ char frame2[9];
+ char frame3[9];
+ char frame4[9];
+ char frame5[9];
+ char frame6[9];
+ char frame7[9];
+ char frame8[9];
+
+} slidename_t;
+
+// villsa [STRIFE] no front/back frames
+typedef struct
+{
+ int frames[8];
+
+} slideframe_t;
+
+// haleyjd 09/29/10: [STRIFE] Externalized for savegames
+void T_SlidingDoor(slidedoor_t* door);
+
+
+// how many frames of animation
+#define SNUMFRAMES 8 // villsa [STRIFE] changed from 4 to 8
+
+#define SDOORWAIT TICRATE*3
+#define SWAITTICS 4
+
+// how many diff. types of anims
+#define MAXSLIDEDOORS 8 // villsa [STRIFE] changed from 5 to 8
+
+void P_InitSlidingDoorFrames(void);
+void EV_SlidingDoor(line_t* line, mobj_t* thing);
+int EV_RemoteSlidingDoor(line_t* line, mobj_t* thing);
+
+
+
+//
+// P_CEILNG
+//
+typedef enum
+{
+ lowerToFloor,
+ raiseToHighest,
+ lowerAndCrush,
+ crushAndRaise,
+ fastCrushAndRaise,
+ silentCrushAndRaise
+
+} ceiling_e;
+
+
+
+typedef struct
+{
+ thinker_t thinker;
+ ceiling_e type;
+ sector_t* sector;
+ fixed_t bottomheight;
+ fixed_t topheight;
+ fixed_t speed;
+ boolean crush;
+
+ // 1 = up, 0 = waiting, -1 = down
+ int direction;
+
+ // ID
+ int tag;
+ int olddirection;
+
+} ceiling_t;
+
+
+
+
+
+#define CEILSPEED FRACUNIT
+#define CEILWAIT 150
+#define MAXCEILINGS 30
+
+extern ceiling_t* activeceilings[MAXCEILINGS];
+
+int
+EV_DoCeiling
+( line_t* line,
+ ceiling_e type );
+
+void T_MoveCeiling (ceiling_t* ceiling);
+void P_AddActiveCeiling(ceiling_t* c);
+void P_RemoveActiveCeiling(ceiling_t* c);
+int EV_CeilingCrushStop(line_t* line);
+void P_ActivateInStasisCeiling(line_t* line);
+
+
+//
+// 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,
+
+ // raise floor to shortest height texture around it
+ raiseToTexture,
+
+ // lower floor to lowest surrounding floor
+ // and change floorpic
+ lowerAndChange,
+
+ raiseFloor64, // [STRIFE] changed from 24 to 64
+ raiseFloor24AndChange,
+ raiseFloorCrush,
+
+ // raise to next highest floor, turbo-speed
+ raiseFloorTurbo,
+ donutRaise,
+ raiseFloor512,
+
+ // [STRIFE] New floor type - used for the coolant reactor pit
+ raiseFloor512AndChange
+
+} floor_e;
+
+
+
+
+typedef enum
+{
+ build8, // slowly build by 8
+ turbo16, // quickly build by 16
+ buildDown16 // haleyjd 09/24/10: [STRIFE] new stair type
+} stair_e;
+
+
+
+typedef struct
+{
+ thinker_t thinker;
+ floor_e type;
+ boolean crush;
+ sector_t* sector;
+ int direction;
+ int newspecial;
+ short texture;
+ fixed_t floordestheight;
+ fixed_t speed;
+
+} floormove_t;
+
+
+
+#define FLOORSPEED FRACUNIT
+
+typedef enum
+{
+ ok,
+ crushed,
+ pastdest
+
+} result_e;
+
+result_e
+T_MovePlane
+( sector_t* sector,
+ fixed_t speed,
+ fixed_t dest,
+ boolean crush,
+ int floorOrCeiling,
+ int direction );
+
+int
+EV_BuildStairs
+( line_t* line,
+ stair_e type );
+
+int
+EV_DoFloor
+( line_t* line,
+ floor_e floortype );
+
+void T_MoveFloor( floormove_t* floor);
+
+//
+// P_TELEPT
+//
+
+// [STRIFE] Teleportation flags - teleflags
+// Not to be conflated with telefrags, though they be tangentially related ;)
+typedef enum teleflags
+{
+ TF_NOSRCSND = 0x01,
+ TF_NODSTSND = 0x02,
+ TF_NODSTFOG = 0x10,
+ TF_NOSRCFOG = 0x20,
+
+ TF_NORMAL = 0,
+ TF_DSTSILENCE = (TF_NODSTSND|TF_NODSTFOG), // 0x12 (18) (Not used)
+ TF_SRCSILENCE = (TF_NOSRCSND|TF_NOSRCFOG), // 0x21 (33)
+ TF_FULLSILENCE = (TF_SRCSILENCE|TF_DSTSILENCE) // 0x33 (51)
+
+} teleflags_e;
+
+int
+EV_Teleport
+( line_t* line,
+ int side,
+ mobj_t* thing,
+ teleflags_e flags);
+
+#endif
diff --git a/src/strife/p_switch.c b/src/strife/p_switch.c
new file mode 100644
index 00000000..bb70f890
--- /dev/null
+++ b/src/strife/p_switch.c
@@ -0,0 +1,1082 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+
+#include "i_system.h"
+#include "deh_main.h"
+#include "doomdef.h"
+#include "p_local.h"
+
+#include "g_game.h"
+#include "d_main.h" // villsa [STRIFE]
+#include "z_zone.h" // villsa [STRIFE]
+#include "w_wad.h" // villsa [STRIFE]
+#include "s_sound.h"
+#include "m_random.h" // haleyjd [STRIFE]
+#include "p_dialog.h"
+#include "p_local.h" // haleyjd [STRIFE]
+#include "m_bbox.h" // villsa [STRIFE]
+
+// Data.
+#include "sounds.h"
+
+// State.
+#include "doomstat.h"
+#include "r_state.h"
+
+//
+// CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE
+//
+// villsa [STRIFE] new switch list
+switchlist_t alphSwitchList[] =
+{
+ { "GLASS01", "GLASS02", 1, sfx_bglass },
+ { "GLASS03", "GLASS04", 1, sfx_bglass },
+ { "GLASS05", "GLASS06", 1, sfx_bglass },
+ { "GLASS07", "GLASS08", 1, sfx_bglass },
+ { "GLASS17", "GLASS18", 1, sfx_bglass },
+ { "GLASS19", "GLASS20", 1, sfx_bglass },
+ { "SWKNOB01", "SWKNOB02", 1, sfx_swknob },
+ { "SWLITE01", "SWLITE02", 1, sfx_None },
+ { "SWCHN01", "SWCHN02", 1, sfx_pulchn },
+ { "COMP01", "COMP04B", 1, sfx_bglass },
+ { "COMP05", "COMP12B", 1, sfx_bglass },
+ { "COMP09", "COMP12B", 1, sfx_bglass },
+ { "COMP12", "COMP04B", 1, sfx_bglass },
+ { "COMP13", "COMP12B", 1, sfx_bglass },
+ { "COMP17", "COMP20B", 1, sfx_bglass },
+ { "COMP21", "COMP28B", 1, sfx_bglass },
+ { "WALTEK09", "WALTEKB1", 1, sfx_None },
+ { "WALTEK10", "WALTEKB1", 1, sfx_None },
+ { "WALTEK15", "WALTEKB1", 1, sfx_None },
+ { "SWFORC01", "SWFORC02", 1, sfx_None },
+ { "SWEXIT01", "SWEXIT02", 1, sfx_None },
+ { "DORSBK01", "DORSBK02", 1, sfx_swston },
+ { "SWSLD01", "SWSLD02", 1, sfx_None },
+ { "DORWS04", "DORWS05", 1, sfx_swbolt },
+ { "SWIRON01", "SWIRON02", 1, sfx_None },
+ { "GLASS09", "GLASS10", 2, sfx_bglass },
+ { "GLASS11", "GLASS12", 2, sfx_bglass },
+ { "GLASS13", "GLASS14", 2, sfx_bglass },
+ { "GLASS15", "GLASS16", 2, sfx_bglass },
+ { "SWFORC03", "SWFORC04", 2, sfx_None },
+ { "SWCIT01", "SWCIT02", 2, sfx_None },
+ { "SWTRMG01", "SWTRMG04", 2, sfx_None },
+ { "SWMETL01", "SWMETL02", 2, sfx_None },
+ { "SWWOOD01", "SWWOOD02", 2, sfx_None },
+ { "SWTKBL01", "SWTKBL02", 2, sfx_None },
+ { "AZWAL21", "AZWAL22", 2, sfx_None },
+ { "SWINDT01", "SWINDT02", 2, sfx_None },
+ { "SWRUST01", "SWRUST02", 2, sfx_None },
+ { "SWCHAP01", "SWCHAP02", 2, sfx_None },
+ { "SWALIN01", "SWALIN02", 2, sfx_None },
+ { "SWWALG01", "SWWALG02", 2, sfx_None },
+ { "SWWALG03", "SWWALG04", 2, sfx_None },
+ { "SWTRAM01", "SWTRAM02", 2, sfx_None },
+ { "SWTRAM03", "SWTRAM04", 2, sfx_None },
+ { "SWORC01", "SWORC02", 2, sfx_None },
+ { "SWBRIK01", "SWBRIK02", 2, sfx_None },
+ { "SWIRON03", "SWIRON04", 2, sfx_None },
+ { "SWIRON05", "SWIRON06", 2, sfx_None },
+ { "SWIRON07", "SWIRON08", 2, sfx_None },
+ { "SWCARD01", "SWCARD02", 2, sfx_keycrd },
+ { "SWSIGN01", "SWSIGN02", 2, sfx_None },
+ { "SWLEV01", "SWLEV02", 2, sfx_None },
+ { "SWLEV03", "SWLEV04", 2, sfx_None },
+ { "SWLEV05", "SWLEV06", 2, sfx_None },
+ { "SWBRN01", "SWBRN02", 2, sfx_keycrd },
+ { "SWPIP01", "SWPIP02", 2, sfx_valve },
+ { "SWPALM01", "SWPALM02", 2, sfx_swscan },
+ { "SWKNOB03", "SWKNOB04", 2, sfx_swknob },
+ { "ALTSW01", "ALTSW02", 2, sfx_None },
+ { "COMP25", "COMP28B", 2, sfx_bglass },
+ { "COMP29", "COMP20B", 2, sfx_bglass },
+ { "COMP33", "COMP50", 2, sfx_bglass },
+ { "COMP42", "COMP51", 2, sfx_bglass },
+ { "GODSCRN1", "GODSCRN2", 2, sfx_difool },
+ { "ALIEN04", "ALIEN05", 2, sfx_None },
+ { "CITADL04", "CITADL05", 2, sfx_None },
+ { "SWITE03", "SWITE04", 2, sfx_None },
+ { "SWTELP01", "SWTELP02", 2, sfx_None },
+ { "BRNSCN01", "BRNSCN05", 2, sfx_firxpl },
+ { "\0", "\0", 0, sfx_None }
+};
+
+int switchlist[MAXSWITCHES * 2];
+int numswitches;
+button_t buttonlist[MAXBUTTONS];
+
+//
+// P_InitSwitchList
+// Only called at game initialization.
+//
+void P_InitSwitchList(void)
+{
+ int i;
+ int index;
+ int episode;
+
+ episode = 1;
+
+ if(isregistered)
+ episode = 2;
+ // villsa [STRIFE] unused
+ /*else
+ if ( gamemode == commercial )
+ episode = 3;*/
+
+ for(index = 0, i = 0; i < MAXSWITCHES; i++)
+ {
+ if(!alphSwitchList[i].episode)
+ {
+ numswitches = index/2;
+ switchlist[index] = -1;
+ break;
+ }
+
+ if (alphSwitchList[i].episode <= episode)
+ {
+ switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name1));
+ switchlist[index++] = R_TextureNumForName(DEH_String(alphSwitchList[i].name2));
+ }
+ }
+}
+
+
+//
+// P_StartButton
+// Start a button counting down till it turns off.
+//
+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)
+ {
+ buttonlist[i].line = line;
+ buttonlist[i].where = w;
+ buttonlist[i].btexture = texture;
+ buttonlist[i].btimer = time;
+ buttonlist[i].soundorg = &line->frontsector->soundorg;
+ return;
+ }
+ }
+
+ I_Error("P_StartButton: no button slots left!");
+}
+
+
+//
+// P_SpawnBrokenGlass
+// villsa [STRIFE] new function
+//
+static void P_SpawnBrokenGlass(line_t* line)
+{
+ fixed_t x1;
+ fixed_t x2;
+ fixed_t y1;
+ fixed_t y2;
+ int i;
+ mobj_t* glass;
+ angle_t an;
+
+ x1 = (line->v2->x + line->v1->x) / 2;
+ y1 = (line->v2->y + line->v1->y) / 2;
+ x2 = ((line->frontsector->soundorg.x - x1) / 5) + x1;
+ y2 = ((line->frontsector->soundorg.y - y1) / 5) + y1;
+
+ for(i = 0; i < 7; i++)
+ {
+ glass = P_SpawnMobj(x2, y2, ONFLOORZ, MT_JUNK);
+ glass->z += (24*FRACUNIT);
+ glass->flags |= (MF_SHADOW|MF_MVIS);
+
+ P_SetMobjState(glass, P_Random() % 3 + S_SHRD_03); // 284
+
+ an = ((P_Random() << 13) / 255);
+
+ glass->angle = (an << ANGLETOFINESHIFT);
+ glass->momx = FixedMul(finecosine[an], (P_Random() & 3) << FRACBITS);
+ glass->momy = FixedMul(finesine[an], (P_Random() & 3) << FRACBITS);
+ glass->momz = (P_Random() & 7) << FRACBITS;
+ glass->tics += (P_Random() + 7) & 7;
+ }
+}
+
+
+//
+// Function that changes wall texture.
+// Tell it if switch is ok to use again (1=yes, it's a button).
+//
+void P_ChangeSwitchTexture(line_t* line, int useAgain)
+{
+ int texTop;
+ int texMid;
+ int texBot;
+ int i;
+ int sound;
+ boolean breakglass; // villsa [STRIFE]
+ switchlist_t* sl; // villsa [STRIFE]
+
+ breakglass = false; // villsa [STRIFE]
+
+ texTop = sides[line->sidenum[0]].toptexture;
+ texMid = sides[line->sidenum[0]].midtexture;
+ texBot = sides[line->sidenum[0]].bottomtexture;
+
+ sound = sfx_swtchn;
+
+ // villsa [STRIFE] check for linetype 182 (break glass)
+ if(line->special == 182)
+ {
+ line->flags &= ~ML_BLOCKING;
+ breakglass = true;
+
+ if(useAgain)
+ {
+ // haleyjd 09/21/10: Corrected (>> 16 == next field)
+ texTop = 0;
+ texBot = 0;
+ }
+
+ if(texMid) // haleyjd 09/21/10: Corrected (>> 16 == next field)
+ useAgain = 0;
+
+ sound = sfx_bglass;
+ }
+
+ if(!useAgain)
+ line->special = 0;
+
+ for(i = 0; i < numswitches*2; i++)
+ {
+ sl = &alphSwitchList[i / 2]; // villsa [STRIFE]
+
+ if(switchlist[i] == texTop)
+ {
+ // villsa [STRIFE] set sound
+ if(sl->sound)
+ sound = sl->sound;
+
+ S_StartSound(buttonlist->soundorg, sound);
+ sides[line->sidenum[0]].toptexture = switchlist[i^1];
+
+ if(useAgain)
+ P_StartButton(line,top,switchlist[i],BUTTONTIME);
+
+ if(breakglass)
+ P_SpawnBrokenGlass(line);
+
+ return;
+ }
+ else
+ {
+ if(switchlist[i] == texMid)
+ {
+ // villsa [STRIFE] set sound
+ if(sl->sound)
+ sound = sl->sound;
+
+ S_StartSound(buttonlist->soundorg,sound);
+ sides[line->sidenum[0]].midtexture = switchlist[i^1];
+
+ // villsa [STRIFE] affect second side of line
+ // BUG: will crash if 1S line is marked with TWOSIDED flag!
+ if(line->flags & ML_TWOSIDED)
+ sides[line->sidenum[1]].midtexture = switchlist[i^1];
+
+ if(useAgain)
+ P_StartButton(line, middle,switchlist[i],BUTTONTIME);
+
+ // villsa [STRIFE]: Mines Transmitter hack
+ if(sound == sfx_firxpl)
+ {
+ breakglass = true;
+
+ // give quest flag 29 to player
+ players[0].questflags |= QF_QUEST29;
+
+ // give stamina/accuracy items
+ if(!netgame)
+ {
+ P_GiveItemToPlayer(players, SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(players, SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ }
+
+ }
+
+ // villsa [STRIFE]
+ if(breakglass || sound == sfx_bglass)
+ P_SpawnBrokenGlass(line);
+
+ return;
+ }
+ else
+ {
+ if(switchlist[i] == texBot)
+ {
+ // villsa [STRIFE] set sound
+ if(sl->sound)
+ sound = sl->sound;
+
+ S_StartSound(buttonlist->soundorg,sound);
+ sides[line->sidenum[0]].bottomtexture = switchlist[i^1];
+
+ if(useAgain)
+ P_StartButton(line, bottom,switchlist[i],BUTTONTIME);
+
+ if(breakglass)
+ P_SpawnBrokenGlass(line);
+
+ return;
+ }
+ }
+ }
+ }
+}
+
+//
+// P_MoveWall
+//
+// villsa [STRIFE] New function.
+// Dynamically move a solid line. Unused in Strife
+//
+static void P_MoveWall(line_t *line, mobj_t *thing)
+{
+ vertex_t *v2;
+ vertex_t *v1;
+ fixed_t x;
+ fixed_t y;
+
+ v1 = line->v1;
+ v2 = line->v2;
+ S_StartSound(thing, sfx_stnmov);
+
+ if (line->dx)
+ {
+ if (thing->x >= v1->x)
+ {
+ v1->y -= (8 * FRACUNIT);
+ v2->y -= (8 * FRACUNIT);
+ }
+ else
+ {
+ v1->y += (8 * FRACUNIT);
+ v2->y += (8 * FRACUNIT);
+ }
+ }
+ else
+ {
+ if (thing->y >= v1->y)
+ {
+ v1->x -= (8 * FRACUNIT);
+ v2->x -= (8 * FRACUNIT);
+ }
+ else
+ {
+ v1->x += (8 * FRACUNIT);
+ v2->x += (8 * FRACUNIT);
+ }
+ }
+
+ if (v1->x >= v2->x)
+ {
+ line->bbox[BOXLEFT] = v2->x;
+ x = v1->x;
+ }
+ else
+ {
+ line->bbox[BOXLEFT] = v1->x;
+ x = v2->x;
+ }
+
+ line->bbox[BOXRIGHT] = x;
+
+ if (v1->y >= v2->y)
+ {
+ line->bbox[BOXBOTTOM] = v2->y;
+ y = v1->y;
+ }
+ else
+ {
+ line->bbox[BOXBOTTOM] = v1->y;
+ y = v2->y;
+ }
+
+ line->bbox[BOXTOP] = y;
+}
+
+// villsa [STRIFE]
+static char usemessage[92];
+
+//
+// P_UseSpecialLine
+// Called when a thing uses a special line.
+// Only the front sides of lines are usable.
+//
+boolean P_UseSpecialLine(mobj_t* thing, line_t* line, int side)
+{
+ // Err...
+ // Use the back sides of VERY SPECIAL lines...
+ if (side)
+ {
+ switch(line->special)
+ {
+ case 148: // haleyjd [STRIFE]
+ break;
+
+ default:
+ 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 31: // haleyjd [STRIFE]
+ case 144: // haleyjd [STRIFE] Manual sliding door
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ }
+
+ // do something
+ switch(line->special)
+ {
+ // MANUALS
+ case 1: // Vertical Door
+ case 26: // DR ID Card
+ case 27: // DR Pass Card
+ case 28: // DR ID Badge
+ case 31: // Manual door open
+ case 32: // D1 ID Card
+ case 33: // D1 ID Badge
+ case 34: // D1 Pass Card
+ case 117: // Blazing door raise
+ case 118: // Blazing door open
+ case 156: // haleyjd [STRIFE] D1 Brass Key
+ case 157: // haleyjd [STRIFE] D1 Silver Key
+ case 158: // haleyjd [STRIFE] D1 Gold Key
+ case 159: // haleyjd [STRIFE] DR Gold Key
+ case 160: // haleyjd [STRIFE] DR Silver Key
+ case 161: // haleyjd [STRIFE] DR Brass Key
+ case 165: // villsa [STRIFE] That doesn't seem to work
+ case 166: // haleyjd [STRIFE] DR Hand Print
+ case 169: // haleyjd [STRIFE] DR Base Key
+ case 170: // haleyjd [STRIFE] DR Gov's Key
+ case 190: // haleyjd [STRIFE] DR Order Key
+ case 205: // villsa [STRIFE] Available in retail only
+ case 213: // haleyjd [STRIFE] DR Chalice
+ case 217: // haleyjd [STRIFE] DR Core Key
+ case 221: // haleyjd [STRIFE] DR Mauler Key
+ case 224: // haleyjd [STRIFE] DR Chapel Key
+ case 225: // haleyjd [STRIFE] DR Catacomb Key
+ case 232: // villsa [STRIFE] DR Oracle Pass
+ EV_VerticalDoor (line, thing);
+ break;
+
+ // haleyjd: For the sake of our sanity, I have reordered all the line
+ // specials from this point down so that they are strictly in numeric
+ // order, and not divided up in a semi-arbitrary fashion.
+
+ case 7:
+ // Build Stairs - [STRIFE] Verified unmodified
+ if (EV_BuildStairs(line,build8))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 9:
+ // Change Donut - [STRIFE] Verified unmodified
+ if (EV_DoDonut(line))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 11:
+ // Exit level - [STRIFE] Modified to take tag, etc.
+ P_ChangeSwitchTexture(line, 1);
+ if(levelTimer && levelTimeCount)
+ break;
+ G_ExitLevel(line->tag);
+ break;
+
+ case 14:
+ // Raise Floor 32 and change texture - [STRIFE] Verified unmodified
+ 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 - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line, raiseFloorToNearest))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 20:
+ // Raise Plat next highest floor and change texture - [STRIFE] Verified unmodified
+ if(EV_DoPlat(line, raiseToNearestAndChange, 0))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 21:
+ // PlatDownWaitUpStay - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, downWaitUpStay,0))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 23:
+ // Lower Floor to Lowest - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,lowerFloorToLowest))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 29:
+ // Raise Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,normal))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 40:
+ // villsa [STRIFE] Split Open Door
+ if(EV_DoDoor(line, splitOpen))
+ P_ChangeSwitchTexture(line, 0);
+ break; // haleyjd
+
+ case 41:
+ // Lower Ceiling to Floor - [STRIFE] Verified unmodified
+ if (EV_DoCeiling(line,lowerToFloor))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 42:
+ // Close Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,close))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 43:
+ // Lower Ceiling to Floor - [STRIFE] Verified unmodified
+ if (EV_DoCeiling(line,lowerToFloor))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 45:
+ // Lower Floor to Surrounding floor height - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,lowerFloor))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 49:
+ // Ceiling Crush And Raise - [STRIFE] Verified unmodified
+ if (EV_DoCeiling(line,crushAndRaise))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 50:
+ // Close Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,close))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 51:
+ // [STRIFE] Modifed into S1 Start Finale (was Secret Exit)
+ P_ChangeSwitchTexture(line,0);
+ G_StartFinale();
+ break;
+
+ case 55:
+ // Raise Floor Crush - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloorCrush))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 60:
+ // Lower Floor to Lowest - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,lowerFloorToLowest))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 61:
+ // Open Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,open))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 62:
+ // PlatDownWaitUpStay - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, downWaitUpStay,1))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 63:
+ // Raise Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,normal))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 64:
+ // Raise Floor to ceiling - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloor))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 65:
+ // Raise Floor Crush - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloorCrush))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 66:
+ // Raise Floor 24 and change texture - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, raiseAndChange, 24))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 67:
+ // Raise Floor 32 and change texture - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, raiseAndChange, 32))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 68:
+ // Raise Plat to next highest floor and change texture - [STRIFE] Verified unmodified
+ if (EV_DoPlat(line, raiseToNearestAndChange, 0))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 69:
+ // Raise Floor to next highest floor - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line, raiseFloorToNearest))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 70:
+ // Turbo Lower Floor - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,turboLower))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 71:
+ // Turbo Lower Floor - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,turboLower))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 101:
+ // Raise Floor - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloor))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 102:
+ // Lower Floor to Surrounding floor height - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,lowerFloor))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 103:
+ // Open Door - [STRIFE] Verified unmodified
+ if (EV_DoDoor(line,open))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 111:
+ // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeRaise))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 112:
+ // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeOpen))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 113:
+ // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeClose))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 114:
+ // Blazing Door Raise (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeRaise))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 115:
+ // Blazing Door Open (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeOpen))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 116:
+ // Blazing Door Close (faster than TURBO!) - [STRIFE] Verified unmodified
+ if (EV_DoDoor (line,blazeClose))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 122:
+ // Blazing PlatDownWaitUpStay - [STRIFE] Verified unmodified
+ if(EV_DoPlat(line, blazeDWUS, 0))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 123:
+ // Blazing PlatDownWaitUpStay - [STRIFE] Verified unmodified
+ if(EV_DoPlat(line, blazeDWUS, 0))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 127:
+ // Build Stairs Turbo 16 - [STRIFE] Verified unmodified
+ if (EV_BuildStairs(line,turbo16))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 131:
+ // Raise Floor Turbo - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloorTurbo))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 132:
+ // Raise Floor Turbo - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloorTurbo))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 133: // [STRIFE] TODO - which key is it?
+ case 135: // [STRIFE] TODO - which key is it?
+ case 137: // [STRIFE] TODO - which key is it?
+ if (EV_DoLockedDoor (line,blazeOpen,thing))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 99: // [STRIFE] TODO: which key is it?
+ case 134: // [STRIFE] TODO: which key is it?
+ case 136: // [STRIFE] TODO: which key is it?
+ if (EV_DoLockedDoor (line,blazeOpen,thing))
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 138:
+ // Light Turn On - [STRIFE] Verified unmodified
+ EV_LightTurnOn(line,255);
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 139:
+ // Light Turn Off - [STRIFE] Verified unmodified
+ EV_LightTurnOn(line,35);
+ P_ChangeSwitchTexture(line,1);
+ break;
+
+ case 140:
+ // Raise Floor 512 - [STRIFE] Verified unmodified
+ if (EV_DoFloor(line,raiseFloor512))
+ P_ChangeSwitchTexture(line,0);
+ break;
+
+ case 144:
+ // villsa [STRIFE] manual sliding door
+ EV_SlidingDoor(line, thing);
+ break;
+
+ case 146:
+ // haleyjd 09/24/10: [STRIFE] S1 Build Stairs Down 16 (new type)
+ if(EV_BuildStairs(line, buildDown16))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 147:
+ // haleyjd 09/24/10: [STRIFE] S1 Clear Force Fields
+ if(EV_ClearForceFields(line))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 148:
+ // haleyjd 09/16/10: [STRIFE] using forcefields hurts
+ P_DamageMobj(thing, NULL, NULL, 16);
+ P_Thrust(thing->player, thing->angle + ANG180, 125*FRACUNIT/16);
+ break;
+
+ case 151: // villsa [STRIFE] BlzOpenDoor Gold key
+ case 152: // [STRIFE] TODO: which key is it?
+ case 153: // [STRIFE] TODO: which key is it?
+ if(EV_DoLockedDoor(line, blazeOpen, thing))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 154:
+ // villsa [STRIFE] plat lower wait rise if have gold key
+ if(thing->player->cards[key_GoldKey])
+ {
+ if(EV_DoPlat(line, downWaitUpStay, 0))
+ P_ChangeSwitchTexture(line, 1);
+ }
+ else
+ {
+ thing->player->message = DEH_String("You need a gold key");
+ S_StartSound(thing, sfx_oof);
+ }
+ break;
+
+ case 155:
+ // villsa [STRIFE] raise plat wait lower
+ if(EV_DoPlat(line, upWaitDownStay, 0))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 162: // [STRIFE] TODO: which key is it?
+ case 163: // [STRIFE] TODO: which key is it?
+ case 164: // villsa [STRIFE] BlzOpenDoor Gold key
+ case 167: // [STRIFE] TODO: which key is it?
+ if(EV_DoLockedDoor(line, blazeOpen, thing))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 168: // [STRIFE] TODO: which key is it?
+ // haleyjd 09/25/10: [STRIFE] SR Blaze Open Door ???? Key
+ if(EV_DoLockedDoor(line, blazeOpen, thing))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 171: // [STRIFE] TODO: which key is it?
+ // haleyjd 09/25/10: [STRIFE] S1 Open Door ???? Key
+ if(EV_DoLockedDoor(line, open, thing))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 172: // [STRIFE] TODO: which key is it?
+ case 173: // [STRIFE] TODO: which key is it?
+ case 176: // [STRIFE] TODO: which key is it?
+ case 191: // [STRIFE] TODO: which key is it?
+ case 192: // [STRIFE] TODO: which key is it?
+ case 223: // [STRIFE] TODO: which key is it?
+ if(EV_DoLockedDoor(line, normal, thing))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 177:
+ // villsa [STRIFE] plat lower wait rise if have power3 key
+ if(thing->player->cards[key_Power3Key])
+ {
+ if(EV_DoPlat(line, downWaitUpStay, 0))
+ P_ChangeSwitchTexture(line, 1);
+ }
+ else
+ {
+ thing->player->message = DEH_String("You don't have the key");
+ S_StartSound(thing, sfx_oof);
+ }
+ break;
+
+ case 181:
+ // haleyjd 09/25/10: [STRIFE] S1 Floor Raise 512 & Change
+ if(EV_DoFloor(line, raiseFloor512AndChange))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 189: // [STRIFE] TODO: which key is it???
+ // haleyjd 09/25/10: [STRIFE] S1 Split Open Door ???? Key
+ if(EV_DoLockedDoor(line, splitOpen, thing))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 194:
+ // villsa [STRIFE] S1 Free Prisoners
+ if(EV_DoDoor(line, open))
+ {
+ P_ChangeSwitchTexture(line, 0);
+ P_FreePrisoners();
+ }
+ break;
+
+ case 199:
+ // haleyjd 09/25/10: [STRIFE] S1 Destroy Converter
+ if(EV_DoCeiling(line, lowerAndCrush))
+ {
+ P_ChangeSwitchTexture(line, 0);
+ P_DestroyConverter();
+ }
+ break;
+
+ case 207:
+ // villsa [STRIFE] SR Remote Sliding Door
+ if(EV_RemoteSlidingDoor(line, thing))
+ P_ChangeSwitchTexture(line, 1);
+ break; // haleyjd
+
+ case 209:
+ // haleyjd 09/24/10: [STRIFE] S1 Build Stairs Down 16 if Have Chalice
+ if(!P_PlayerHasItem(thing->player, MT_INV_CHALICE))
+ {
+ DEH_snprintf(usemessage, sizeof(usemessage), "You need the chalice!");
+ thing->player->message = usemessage;
+ S_StartSound(thing, sfx_oof);
+ break;
+ }
+ else if(EV_BuildStairs(line, buildDown16))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 211:
+ // villsa [STRIFE] S1 Play VOC## sound
+ if(&players[consoleplayer] == thing->player &&
+ thing->player->powers[pw_communicator])
+ {
+ DEH_snprintf(usemessage, sizeof(usemessage), "voc%i", line->tag);
+ I_StartVoice(usemessage);
+ line->special = 0;
+ }
+ break;
+
+ case 214:
+ // villsa [STRIFE] S1 slow lift lower wait up stay
+ if(EV_DoPlat(line, slowDWUS, 1))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 219:
+ // haleyjd 09/25/10: S1 Lower Floor Blue Crystal
+ if(!thing->player->cards[key_BlueCrystalKey])
+ {
+ thing->player->message = DEH_String("You need the Blue Crystal");
+ S_StartSound(thing, sfx_oof);
+ }
+ else if(EV_DoFloor(line, lowerFloor))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 220:
+ // haleyjd 09/25/10: S1 Lower Floor Red Crystal
+ if(!thing->player->cards[key_RedCrystalKey])
+ {
+ thing->player->message = DEH_String("You need the Red Crystal");
+ S_StartSound(thing, sfx_oof);
+ }
+ else if(EV_DoFloor(line, lowerFloor))
+ P_ChangeSwitchTexture(line, 0);
+ break;
+
+ case 226:
+ // villsa [STRIFE] S1 Complete Training Area
+ if(EV_DoFloor(line, lowerFloor))
+ {
+ P_GiveItemToPlayer(thing->player, SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(thing->player, SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ P_ChangeSwitchTexture(line, 0);
+ DEH_snprintf(usemessage, sizeof(usemessage),
+ DEH_String("Congratulations! You have completed the training area."));
+ thing->player->message = usemessage;
+ }
+ break;
+
+ case 229:
+ // villsa [STRIFE] SR Sigil Sliding Door
+ if(thing->player->sigiltype == 4)
+ {
+ if(EV_RemoteSlidingDoor(line, thing))
+ P_ChangeSwitchTexture(line, 1);
+ }
+ break; // haleyjd
+
+ case 233:
+ // villsa [STRIFE] objective given after revealing the computer
+ if(!EV_DoDoor(line, splitOpen))
+ return true;
+
+ P_ChangeSwitchTexture(line, 1);
+ GiveVoiceObjective("voc70", "log70", 0);
+
+ // haleyjd: Strife used sprintf here, not a direct set.
+ DEH_snprintf(usemessage, sizeof(usemessage),
+ "Incoming Message from BlackBird...");
+ thing->player->message = usemessage;
+
+ break;
+
+ case 234:
+ // haleyjd 09/24/10: [STRIFE] SR Raise Door if Quest 3
+ if(!(thing->player->questflags & QF_QUEST3)) // QUEST3 == Irale
+ {
+ // BUG: doesn't make sfx_oof sound like all other message-
+ // giving door types. I highly doubt this was intentional.
+ DEH_snprintf(usemessage, sizeof(usemessage),
+ "That doesn't seem to work!");
+ thing->player->message = usemessage;
+ }
+ else if(EV_DoDoor(line, normal))
+ P_ChangeSwitchTexture(line, 1);
+ break;
+
+ case 235:
+ // haleyjd 09/25/10: [STRIFE] S1 Split Open Door if Have Sigil 4
+ if(thing->player->sigiltype == 4)
+ {
+ if(EV_DoDoor(line, splitOpen))
+ P_ChangeSwitchTexture(line, 0);
+ }
+ break;
+
+ case 666:
+ // villsa [STRIFE] SR Move Wall
+ P_MoveWall(line, thing);
+ break;
+ }
+
+ return true;
+}
+
diff --git a/src/strife/p_telept.c b/src/strife/p_telept.c
new file mode 100644
index 00000000..b6928b27
--- /dev/null
+++ b/src/strife/p_telept.c
@@ -0,0 +1,160 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 "s_sound.h"
+
+#include "p_local.h"
+
+
+// Data.
+#include "sounds.h"
+
+// State.
+#include "r_state.h"
+
+
+
+//
+// TELEPORTATION
+//
+// haleyjd 09/22/10: [STRIFE] Modified to take a flags parameter to control
+// silent teleportation. Rogue also removed the check for missiles, and the
+// z-set was replaced with one in P_TeleportMove.
+//
+int
+EV_Teleport
+( line_t* line,
+ int side,
+ mobj_t* thing,
+ teleflags_e flags)
+{
+ int i;
+ int tag;
+ mobj_t* m;
+ mobj_t* fog = NULL;
+ unsigned an;
+ thinker_t* thinker;
+ sector_t* sector;
+ fixed_t oldx;
+ fixed_t oldy;
+ fixed_t oldz;
+
+ // haleyjd 20110205 [STRIFE]: this is not checked here
+ // don't teleport missiles
+ //if (thing->flags & MF_MISSILE)
+ // return 0;
+
+ // Don't teleport if hit back of line,
+ // so you can get out of teleporter.
+ if (side == 1)
+ return 0;
+
+ tag = line->tag;
+ for (i = 0; i < numsectors; i++)
+ {
+ if (sectors[ i ].tag == tag )
+ {
+ thinker = thinkercap.next;
+ for (thinker = thinkercap.next;
+ thinker != &thinkercap;
+ thinker = thinker->next)
+ {
+ // not a mobj
+ if (thinker->function.acp1 != (actionf_p1)P_MobjThinker)
+ continue;
+
+ m = (mobj_t *)thinker;
+
+ // not a teleportman
+ if (m->type != MT_TELEPORTMAN )
+ continue;
+
+ sector = m->subsector->sector;
+ // wrong sector
+ if (sector-sectors != i )
+ continue;
+
+ oldx = thing->x;
+ oldy = thing->y;
+ oldz = thing->z;
+
+ if (!P_TeleportMove (thing, m->x, m->y))
+ return 0;
+
+ // fraggle: this was changed in final doom,
+ // problem between normal doom2 1.9 and final doom
+ //
+ // Note that although chex.exe is based on Final Doom,
+ // it does not have this quirk.
+ //
+ // haleyjd 20110205 [STRIFE] This code is *not* present,
+ // because of a z-set which Rogue added to P_TeleportMove.
+ /*
+ if (gameversion < exe_final || gameversion == exe_chex)
+ thing->z = thing->floorz;
+ */
+
+ if (thing->player)
+ thing->player->viewz = thing->z+thing->player->viewheight;
+
+ // spawn teleport fog at source and destination
+ // haleyjd 09/22/10: [STRIFE] controlled by teleport flags
+ // BUG: Behavior would be undefined if this function were passed
+ // any combination of teleflags that has the NO*FOG but not the
+ // corresponding NO*SND flag - fortunately this is never done
+ // anywhere in the code.
+ if(!(flags & TF_NOSRCFOG))
+ fog = P_SpawnMobj (oldx, oldy, oldz, MT_TFOG);
+ if(!(flags & TF_NOSRCSND))
+ S_StartSound (fog, sfx_telept);
+
+ an = m->angle >> ANGLETOFINESHIFT;
+
+ if(!(flags & TF_NODSTFOG))
+ fog = P_SpawnMobj (m->x+20*finecosine[an], m->y+20*finesine[an],
+ thing->z, MT_TFOG);
+ if(!(flags & TF_NODSTSND))
+ S_StartSound (fog, sfx_telept);
+
+ // don't move for a bit
+ if (thing->player)
+ thing->reactiontime = 18;
+
+ thing->angle = m->angle;
+ thing->momx = thing->momy = thing->momz = 0;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/src/strife/p_tick.c b/src/strife/p_tick.c
new file mode 100644
index 00000000..4a7ead62
--- /dev/null
+++ b/src/strife/p_tick.c
@@ -0,0 +1,165 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+// Thinker, Ticker.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "z_zone.h"
+#include "p_local.h"
+
+#include "doomstat.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;
+
+
+//
+// P_InitThinkers
+//
+// [STRIFE] Verified unmodified
+//
+void P_InitThinkers (void)
+{
+ thinkercap.prev = thinkercap.next = &thinkercap;
+}
+
+
+
+
+//
+// P_AddThinker
+// Adds a new thinker at the end of the list.
+//
+// [STRIFE] Verified unmodified
+//
+void P_AddThinker (thinker_t* thinker)
+{
+ thinkercap.prev->next = thinker;
+ thinker->next = &thinkercap;
+ thinker->prev = thinkercap.prev;
+ thinkercap.prev = thinker;
+}
+
+
+
+//
+// P_RemoveThinker
+// Deallocation is lazy -- it will not actually be freed
+// until its thinking turn comes up.
+//
+// [STRIFE] Verified unmodified
+//
+void P_RemoveThinker (thinker_t* thinker)
+{
+ // FIXME: NOP.
+ thinker->function.acv = (actionf_v)(-1);
+}
+
+
+
+//
+// P_AllocateThinker
+// Allocates memory and adds a new thinker at the end of the list.
+//
+void P_AllocateThinker (thinker_t* thinker)
+{
+}
+
+//
+// P_RunThinkers
+//
+// [STRIFE] Verified unmodified
+//
+void P_RunThinkers (void)
+{
+ thinker_t* currentthinker;
+
+ currentthinker = thinkercap.next;
+ while (currentthinker != &thinkercap)
+ {
+ if ( currentthinker->function.acv == (actionf_v)(-1) )
+ {
+ // time to remove it
+ currentthinker->next->prev = currentthinker->prev;
+ currentthinker->prev->next = currentthinker->next;
+ Z_Free (currentthinker);
+ }
+ else
+ {
+ if (currentthinker->function.acp1)
+ currentthinker->function.acp1 (currentthinker);
+ }
+ currentthinker = currentthinker->next;
+ }
+}
+
+//
+// P_Ticker
+//
+// [STRIFE] Menu pause behavior modified
+//
+void P_Ticker (void)
+{
+ int i;
+
+ // run the tic
+ if (paused)
+ return;
+
+ // pause if in menu and at least one tic has been run
+ // haleyjd 09/08/10 [STRIFE]: menuactive -> menupause
+ if (!netgame
+ && menupause
+ && !demoplayback
+ && players[consoleplayer].viewz != 1)
+ {
+ return;
+ }
+
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ if (playeringame[i])
+ P_PlayerThink (&players[i]);
+
+ P_RunThinkers ();
+ P_UpdateSpecials ();
+ P_RespawnSpecials ();
+
+ // for par times
+ leveltime++;
+}
diff --git a/src/strife/p_tick.h b/src/strife/p_tick.h
new file mode 100644
index 00000000..06934bb8
--- /dev/null
+++ b/src/strife/p_tick.h
@@ -0,0 +1,41 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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:
+// ?
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __P_TICK__
+#define __P_TICK__
+
+
+
+
+// Called by C_Ticker,
+// can call G_PlayerExited.
+// Carries out all thinking of monsters and players.
+void P_Ticker (void);
+
+
+
+#endif
diff --git a/src/strife/p_user.c b/src/strife/p_user.c
new file mode 100644
index 00000000..aa2ba430
--- /dev/null
+++ b/src/strife/p_user.c
@@ -0,0 +1,922 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdlib.h>
+
+#include "doomdef.h"
+#include "d_event.h"
+#include "p_local.h"
+#include "sounds.h" // villsa [STRIFE]
+#include "p_dialog.h" // villsa [STRIFE]
+#include "d_main.h" // villsa [STRIFE]
+#include "doomstat.h"
+#include "deh_str.h" // haleyjd [STRIFE]
+#include "z_zone.h"
+#include "w_wad.h"
+#include "p_pspr.h"
+#include "m_random.h"
+#include "s_sound.h"
+#include "p_inter.h"
+
+
+
+// Index of the special effects (INVUL inverse) map.
+#define LOOKPITCHAMOUNT 6 // villsa [STRIFE]
+#define CENTERVIEWAMOUNT (LOOKPITCHAMOUNT + 2) // villsa [STRIFE]
+#define LOOKUPMAX 90 // villsa [STRIFE]
+#define LOOKDOWNMAX -110 // villsa [STRIFE]
+
+
+void P_DropInventoryItem(player_t* player, int sprite); // villsa [STRIFE]
+boolean P_ItemBehavior(player_t* player, int item); // villsa [STRIFE]
+static char useinventorymsg[44]; // villsa [STRIFE]
+
+//
+// Movement.
+//
+
+// 16 pixels of bob
+#define MAXBOB 0x100000
+
+boolean onground;
+
+
+//
+// P_Thrust
+// Moves the given origin along a given angle.
+//
+// [STRIFE] Verified unmodified
+//
+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_CalcHeight
+// Calculate the walking / running height adjustment
+//
+// [STRIFE] Some odd adjustments, and terrain view 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.
+ player->bob =
+ FixedMul (player->mo->momx, player->mo->momx)
+ + FixedMul (player->mo->momy,player->mo->momy);
+
+ player->bob >>= 2;
+
+ if (player->bob>MAXBOB)
+ player->bob = MAXBOB;
+
+ // haleyjd 20110205 [STRIFE]: No CF_NOMOMENTUM check, and Rogue also removed
+ // the dead code inside.
+ if (!onground)
+ {
+ /*
+ player->viewz = player->mo->z + VIEWHEIGHT;
+
+ if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
+ player->viewz = player->mo->ceilingz-4*FRACUNIT;
+ */
+
+ 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;
+
+ // villsa [STRIFE] account for terrain lowering the view
+ if(player->mo->flags & MF_FEETCLIPPED)
+ player->viewz -= 13*FRACUNIT;
+
+ if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
+ player->viewz = player->mo->ceilingz-4*FRACUNIT;
+
+ // haleyjd [STRIFE]: added a floorz clip here
+ if (player->viewz < player->mo->floorz)
+ player->viewz = player->mo->floorz;
+}
+
+
+
+//
+// P_MovePlayer
+//
+// [STRIFE] Adjustments to allow air control, jumping, and up/down look.
+//
+void P_MovePlayer (player_t* player)
+{
+ ticcmd_t* cmd;
+
+ cmd = &player->cmd;
+
+ player->mo->angle += (cmd->angleturn<<16);
+
+ // Do not let the player control movement
+ // if not onground.
+ onground = (player->mo->z <= player->mo->floorz);
+
+ // villsa [STRIFE] allows player to climb over things by jumping
+ // haleyjd 20110205: air control thrust should be 256, not cmd->forwardmove
+ if(!onground)
+ {
+ if(cmd->forwardmove)
+ P_Thrust (player, player->mo->angle, 256);
+ }
+ else
+ {
+ // villsa [STRIFE] jump button
+ if (cmd->buttons2 & BT2_JUMP)
+ {
+ if(!player->deltaviewheight)
+ player->mo->momz += 8*FRACUNIT;
+ }
+
+ // haleyjd 20110205 [STRIFE] Either Rogue or Watcom removed the
+ // redundant "onground" checks from these if's.
+ if (cmd->forwardmove)
+ P_Thrust (player, player->mo->angle, cmd->forwardmove*2048);
+
+ if (cmd->sidemove)
+ P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048);
+ }
+
+ // villsa [STRIFE] player walking state set
+ if ( (cmd->forwardmove || cmd->sidemove)
+ && player->mo->state == &states[S_PLAY_00] )
+ {
+ P_SetMobjState (player->mo, S_PLAY_01);
+ }
+
+ // villsa [STRIFE] centerview button
+ if (cmd->buttons2 & BT2_CENTERVIEW)
+ player->centerview = 1;
+
+ // villsa [STRIFE] adjust player's pitch when centerviewing
+ if (player->centerview)
+ {
+ if (player->pitch <= 0)
+ {
+ if (player->pitch < 0)
+ player->pitch = player->pitch + CENTERVIEWAMOUNT;
+ }
+ else
+ {
+ player->pitch = player->pitch - CENTERVIEWAMOUNT;
+ }
+ if (abs(player->pitch) < CENTERVIEWAMOUNT)
+ {
+ player->pitch = 0;
+ player->centerview = 0;
+ }
+ }
+
+ // villsa [STRIFE] look up action
+ if (cmd->buttons2 & BT2_LOOKUP)
+ {
+ player->pitch += LOOKPITCHAMOUNT;
+ if ((player->pitch + LOOKPITCHAMOUNT) > LOOKUPMAX ||
+ (player->pitch + LOOKPITCHAMOUNT) < LOOKDOWNMAX)
+ player->pitch -= LOOKPITCHAMOUNT;
+ }
+ else
+ {
+ // villsa [STRIFE] look down action
+ if (cmd->buttons2 & BT2_LOOKDOWN)
+ {
+ player->pitch -= LOOKPITCHAMOUNT;
+ if ((player->pitch - LOOKPITCHAMOUNT) > LOOKUPMAX ||
+ (player->pitch - LOOKPITCHAMOUNT) < LOOKDOWNMAX)
+ player->pitch += LOOKPITCHAMOUNT;
+ }
+ }
+
+}
+
+
+
+//
+// P_DeathThink
+// Fall on your face when dying.
+// Decrease POV height to floor height.
+//
+// [STRIFE] Modifications for up/down look.
+//
+#define ANG5 (ANG90/18)
+
+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--;
+
+ // villsa [STRIFE]
+ if(player->pitch <= 90)
+ player->pitch = player->pitch + 3;
+
+ if(player->cmd.buttons & BT_USE)
+ player->playerstate = PST_REBORN;
+}
+
+
+
+//
+// P_PlayerThink
+//
+// [STRIFE] Massive changes/additions:
+// * NOCLIP hack removed
+// * P_DeathThink moved up
+// * Inventory use/dropping
+// * Strife weapons logic
+// * Dialog
+// * Strife powerups and nukage behavior
+// * Fire Death/Sigil Shock
+//
+void P_PlayerThink (player_t* player)
+{
+ ticcmd_t* cmd;
+ weapontype_t newweapon;
+
+ // villsa [STRIFE] unused code (see ST_Responder)
+ /*
+ // fixme: do this in the cheat code
+ if (player->cheats & CF_NOCLIP)
+ player->mo->flags |= MF_NOCLIP;
+ else
+ player->mo->flags &= ~MF_NOCLIP;
+ */
+
+ // haleyjd 20110205 [STRIFE]: P_DeathThink moved up
+ if (player->playerstate == PST_DEAD)
+ {
+ P_DeathThink (player);
+ return;
+ }
+
+ // 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;
+ }
+
+ // 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);
+
+ if (player->mo->subsector->sector->special)
+ P_PlayerInSpecialSector (player);
+
+ // villsa [STRIFE] handle inventory input
+ if(cmd->buttons2 & (BT2_HEALTH|BT2_INVUSE|BT2_INVDROP))
+ {
+ if(!player->inventorydown)
+ {
+ if(cmd->buttons2 & BT2_HEALTH)
+ P_UseInventoryItem(player, SPR_FULL);
+ else if(cmd->buttons2 & BT2_INVUSE)
+ P_UseInventoryItem(player, cmd->inventory);
+ else if(cmd->buttons2 & BT2_INVDROP)
+ {
+ P_DropInventoryItem(player, cmd->inventory);
+
+ // haleyjd 20110205: removed incorrect "else" here
+ // villsa [STRIFE]
+ if(workparm)
+ {
+ int cheat = player->cheats ^ 1;
+ player->cheats ^= CF_NOCLIP;
+
+ if(cheat & CF_NOCLIP)
+ {
+ player->message = DEH_String("No Clipping Mode ON");
+ player->mo->flags |= MF_NOCLIP;
+ }
+ else
+ {
+ player->mo->flags &= ~MF_NOCLIP;
+ player->message = DEH_String("No Clipping Mode OFF");
+ }
+ }
+ }
+ }
+
+ player->inventorydown = true;
+ }
+ else
+ player->inventorydown = false;
+
+ // Check for weapon change.
+
+ // A special event has no other buttons.
+ if(cmd->buttons & BT_SPECIAL)
+ cmd->buttons = 0;
+
+ 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;
+
+ // villsa [STRIFE] select poison bow
+ if(newweapon == wp_elecbow)
+ {
+ if(player->weaponowned[wp_poisonbow] && player->readyweapon == wp_elecbow)
+ {
+ if(player->ammo[weaponinfo[wp_poisonbow].ammo])
+ newweapon = wp_poisonbow;
+ }
+ }
+
+ // villsa [STRIFE] select wp grenade launcher
+ if(newweapon == wp_hegrenade)
+ {
+ if(player->weaponowned[wp_wpgrenade] && player->readyweapon == wp_hegrenade)
+ {
+ if(player->ammo[weaponinfo[wp_wpgrenade].ammo])
+ newweapon = wp_wpgrenade;
+ }
+ }
+
+ // villsa [STRIFE] select torpedo
+ if(newweapon == wp_mauler)
+ {
+ if(player->weaponowned[wp_torpedo] && player->readyweapon == wp_mauler)
+ {
+ if(player->ammo[weaponinfo[am_cell].ammo] >= 30)
+ newweapon = wp_torpedo;
+ }
+ }
+
+ if(player->weaponowned[newweapon] && newweapon != player->readyweapon)
+ {
+ // villsa [STRIFE] check weapon if in demo mode or not
+ if(weaponinfo[newweapon].availabledemo || !isdemoversion)
+ {
+ if(player->ammo[weaponinfo[newweapon].ammo])
+ player->pendingweapon = newweapon;
+ else
+ {
+ // decide between electric bow or poison arrow
+ if(newweapon == wp_elecbow &&
+ player->ammo[am_poisonbolts] &&
+ player->readyweapon != wp_poisonbow)
+ {
+ player->pendingweapon = wp_poisonbow;
+ }
+ // decide between hp grenade launcher or wp grenade launcher
+ else if(newweapon == wp_hegrenade &&
+ player->ammo[am_wpgrenades] &&
+ player->readyweapon != wp_wpgrenade)
+ {
+ player->pendingweapon = wp_wpgrenade;
+ }
+
+ // villsa [STRIFE] - no check for mauler/torpedo??
+ }
+ }
+ }
+ }
+
+ // check for use
+ if(cmd->buttons & BT_USE)
+ {
+ if(!player->usedown)
+ {
+ P_DialogStart(player); // villsa [STRIFE]
+ P_UseLines (player);
+ player->usedown = true;
+ }
+ }
+ else
+ player->usedown = false;
+
+ // cycle psprites
+ P_MovePsprites (player);
+
+ // Counters, time dependend power ups.
+
+ // Strength counts up to diminish fade.
+ if (player->powers[pw_strength])
+ player->powers[pw_strength]++;
+
+ // villsa [STRIFE] targeter powerup
+ if(player->powers[pw_targeter])
+ {
+ player->powers[pw_targeter]--;
+ if(player->powers[pw_targeter] == 1)
+ {
+ P_SetPsprite(player, ps_targcenter, S_NULL);
+ P_SetPsprite(player, ps_targleft, S_NULL);
+ P_SetPsprite(player, ps_targright, S_NULL);
+ }
+ else if(player->powers[pw_targeter] - 1 < 5*TICRATE)
+ {
+ if(player->powers[pw_targeter] & 32)
+ {
+ P_SetPsprite(player, ps_targright, S_NULL);
+ P_SetPsprite(player, ps_targleft, S_TRGT_01); // 11
+ }
+ else if(player->powers[pw_targeter] & 16) // haleyjd 20110205: missing else
+ {
+ P_SetPsprite(player, ps_targright, S_TRGT_02); // 12
+ P_SetPsprite(player, ps_targleft, S_NULL);
+ }
+ }
+ }
+
+ if(player->powers[pw_invisibility])
+ {
+ // villsa [STRIFE] remove mvis flag as well
+ if(!--player->powers[pw_invisibility])
+ player->mo->flags &= ~(MF_SHADOW|MF_MVIS);
+ }
+
+ if(player->powers[pw_ironfeet])
+ {
+ player->powers[pw_ironfeet]--;
+
+ // villsa [STRIFE] gasmask sound
+ if(!(leveltime & 0x3f))
+ S_StartSound(player->mo, sfx_mask);
+ }
+
+ if(player->powers[pw_allmap] > 1)
+ player->powers[pw_allmap]--;
+
+ // haleyjd 08/30/10: [STRIFE]
+ // Nukage count keeps track of exposure to hazardous conditions over time.
+ // After accumulating 16 total seconds or more of exposure, you will take
+ // 5 damage roughly once per second until the count drops back under 560
+ // tics.
+ if(player->nukagecount)
+ {
+ player->nukagecount--;
+ if(!(leveltime & 0x1f) && player->nukagecount > 16*TICRATE)
+ P_DamageMobj(player->mo, NULL, NULL, 5);
+ }
+
+ if(player->damagecount)
+ player->damagecount--;
+
+ if(player->bonuscount)
+ player->bonuscount--;
+
+ // villsa [STRIFE] checks for extralight
+ if(player->extralight >= 0)
+ {
+ if(player->cheats & CF_ONFIRE)
+ player->fixedcolormap = 1;
+ else
+ player->fixedcolormap = 0;
+ }
+ else // Sigil shock:
+ player->fixedcolormap = INVERSECOLORMAP;
+}
+
+
+//
+// P_RemoveInventoryItem
+// villsa [STRIFE] new function
+//
+char* P_RemoveInventoryItem(player_t *player, int slot, int amount)
+{
+ mobjtype_t type;
+
+ player->inventory[slot].amount -= amount;
+ player->st_update = true;
+
+ type = player->inventory[slot].type;
+
+ if(!player->inventory[slot].amount)
+ {
+ // shift everything above it down
+ // see P_TakeDialogItem for notes on possible bugs
+ int j;
+
+ for(j = slot + 1; j <= player->numinventory; j++)
+ {
+ inventory_t *item1 = &(player->inventory[j - 1]);
+ inventory_t *item2 = &(player->inventory[j]);
+
+ *item1 = *item2;
+ }
+
+ player->inventory[player->numinventory].type = NUMMOBJTYPES;
+ player->inventory[player->numinventory].sprite = -1;
+ player->numinventory--;
+
+ // update cursor position
+ if(player->inventorycursor >= player->numinventory)
+ {
+ if(player->inventorycursor)
+ player->inventorycursor--;
+ }
+ }
+
+ return mobjinfo[type].name;
+}
+
+//
+// P_DropInventoryItem
+// villsa [STRIFE] new function
+//
+void P_DropInventoryItem(player_t* player, int sprite)
+{
+ int invslot;
+ inventory_t *item;
+ mobjtype_t type;
+ int amount;
+
+ invslot = 0;
+ amount = 1;
+
+ while(invslot < player->numinventory && sprite != player->inventory[invslot].sprite)
+ invslot++;
+
+ item = &(player->inventory[invslot]);
+ type = item->type;
+
+ if(item->amount)
+ {
+ angle_t angle;
+ fixed_t dist;
+ mobj_t* mo;
+ mobj_t* mobjitem;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ int r;
+
+ if(item->type == MT_MONY_1)
+ {
+ if(item->amount >= 50)
+ {
+ type = MT_MONY_50;
+ amount = 50;
+ }
+ else if(item->amount >= 25)
+ {
+ type = MT_MONY_25;
+ amount = 25;
+ }
+ else if(item->amount >= 10)
+ {
+ type = MT_MONY_10;
+ amount = 10;
+ }
+ }
+
+ if(type >= NUMMOBJTYPES)
+ return;
+
+ angle = player->mo->angle;
+ r = P_Random();
+ angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT;
+
+ if(angle < 7618 && angle >= 6718)
+ angle = 7618;
+
+ else if(angle < 5570 && angle >= 4670)
+ angle = 5570;
+
+ else if(angle < 3522 && angle >= 2622)
+ angle = 3522;
+
+ else if(angle < 1474 && angle >= 574)
+ angle = 1474;
+
+ mo = player->mo;
+ dist = mobjinfo[type].radius + mo->info->radius + (4*FRACUNIT);
+
+ x = mo->x + FixedMul(finecosine[angle], dist);
+ y = mo->y + FixedMul(finesine[angle], dist);
+ z = mo->z + (10*FRACUNIT);
+ mobjitem = P_SpawnMobj(x, y, z, type);
+ mobjitem->flags |= (MF_SPECIAL|MF_DROPPED);
+
+ if(P_CheckPosition(mobjitem, x, y))
+ {
+ mobjitem->angle = (angle << ANGLETOFINESHIFT);
+ mobjitem->momx = FixedMul(finecosine[angle], (5*FRACUNIT)) + mo->momx;
+ mobjitem->momy = FixedMul(finesine[angle], (5*FRACUNIT)) + mo->momy;
+ mobjitem->momz = FRACUNIT;
+
+ P_RemoveInventoryItem(player, invslot, amount);
+ }
+ else
+ P_RemoveMobj(mobjitem);
+ }
+}
+
+//
+// P_TossDegninOre
+// villsa [STRIFE] new function
+//
+boolean P_TossDegninOre(player_t* player)
+{
+ angle_t angle;
+ mobj_t* mo;
+ mobj_t* ore;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ fixed_t dist;
+
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+
+ if(angle < 7618 && angle >= 6718)
+ angle = 7618;
+
+ else if(angle < 5570 && angle >= 4670)
+ angle = 5570;
+
+ else if(angle < 3522 && angle >= 2622)
+ angle = 3522;
+
+ else if(angle < 1474 && angle >= 574)
+ angle = 1474;
+
+ mo = player->mo;
+ dist = mobjinfo[MT_DEGNINORE].radius + mo->info->radius + (4*FRACUNIT);
+
+ x = mo->x + FixedMul(finecosine[angle], dist);
+ y = mo->y + FixedMul(finesine[angle], dist);
+ z = mo->z + (10*FRACUNIT);
+ ore = P_SpawnMobj(x, y, z, MT_DEGNINORE);
+
+ if(P_CheckPosition(ore, x, y))
+ {
+ ore->target = mo;
+ ore->angle = (angle << ANGLETOFINESHIFT);
+ ore->momx = FixedMul(finecosine[angle], (5*FRACUNIT));
+ ore->momy = FixedMul(finesine[angle], (5*FRACUNIT));
+ ore->momz = FRACUNIT;
+ return true;
+ }
+ else
+ P_RemoveMobj(ore);
+
+ return false;
+}
+
+//
+// P_SpawnTeleportBeacon
+// villsa [STRIFE] new function
+//
+boolean P_SpawnTeleportBeacon(player_t* player)
+{
+ angle_t angle;
+ int r;
+ mobj_t* mo;
+ mobj_t* beacon;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ fixed_t dist;
+
+ angle = player->mo->angle;
+ r = P_Random();
+ angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT;
+
+ if(angle < 7618 && angle >= 6718)
+ angle = 7618;
+
+ else if(angle < 5570 && angle >= 4670)
+ angle = 5570;
+
+ else if(angle < 3522 && angle >= 2622)
+ angle = 3522;
+
+ else if(angle < 1474 && angle >= 574)
+ angle = 1474;
+
+ mo = player->mo;
+ dist = mobjinfo[MT_BEACON].radius + mo->info->radius + (4*FRACUNIT);
+
+ x = mo->x + FixedMul(finecosine[angle], dist);
+ y = mo->y + FixedMul(finesine[angle], dist);
+ z = mo->z + (10*FRACUNIT);
+ beacon = P_SpawnMobj(x, y, z, MT_BEACON);
+
+ if(P_CheckPosition(beacon, x, y))
+ {
+ beacon->target = mo;
+ beacon->miscdata = mo->miscdata;
+ beacon->angle = (angle << ANGLETOFINESHIFT);
+ beacon->momx = FixedMul(finecosine[angle], (5*FRACUNIT));
+ beacon->momy = FixedMul(finesine[angle], (5*FRACUNIT));
+ beacon->momz = FRACUNIT;
+ P_SetMobjState(beacon, beacon->info->seestate);
+ return true;
+ }
+ else
+ P_RemoveMobj(beacon);
+
+ return false;
+}
+
+//
+// P_UseInventoryItem
+// villsa [STRIFE] new function
+//
+boolean P_UseInventoryItem(player_t* player, int item)
+{
+ int i;
+ char* name;
+
+ if(player->cheats & CF_ONFIRE)
+ return false;
+
+ for(i = 0; i < player->numinventory; i++)
+ {
+ if(item != player->inventory[i].sprite)
+ continue;
+
+ if(!P_ItemBehavior(player, item))
+ return false;
+
+ name = P_RemoveInventoryItem(player, i, 1);
+ if(name == NULL)
+ name = "Item";
+
+ sprintf(useinventorymsg, "You used the %s.", name);
+ player->message = useinventorymsg;
+
+ if(player == &players[consoleplayer])
+ S_StartSound(NULL, sfx_itemup);
+
+ return true;
+ }
+
+ return false;
+}
+
+//
+// P_ItemBehavior
+// villsa [STRIFE] new function
+//
+boolean P_ItemBehavior(player_t* player, int item)
+{
+ switch(item)
+ {
+ case SPR_ARM1: // 136
+ return P_GiveArmor(player, 2);
+
+ case SPR_ARM2: // 137
+ return P_GiveArmor(player, 1);
+
+ case SPR_SHD1: // 186
+ return P_GivePower(player, pw_invisibility);
+
+ case SPR_MASK: // 187
+ return P_GivePower(player, pw_ironfeet);
+
+ case SPR_PMUP: // 191
+ if(!player->powers[pw_allmap])
+ {
+ player->message = "The scanner won't work without a map!";
+ return false;
+ }
+ player->powers[pw_allmap] = PMUPTICS;
+ return true; // haleyjd 20110228: repaired
+
+ case SPR_STMP: // 180
+ return P_GiveBody(player, 10);
+
+ case SPR_MDKT: // 181
+ return P_GiveBody(player, 25);
+
+ case SPR_FULL: // 130
+ return P_GiveBody(player, 200);
+
+ case SPR_BEAC: // 135
+ return P_SpawnTeleportBeacon(player);
+
+ case SPR_TARG: // 108
+ return P_GivePower(player, pw_targeter);
+ }
+
+ return false;
+}
diff --git a/src/strife/r_bsp.c b/src/strife/r_bsp.c
new file mode 100644
index 00000000..ee05156d
--- /dev/null
+++ b/src/strife/r_bsp.c
@@ -0,0 +1,581 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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_local.h"
+
+
+
+seg_t* curline;
+side_t* sidedef;
+line_t* linedef;
+sector_t* frontsector;
+sector_t* backsector;
+
+drawseg_t drawsegs[MAXDRAWSEGS];
+drawseg_t* ds_p;
+
+
+void
+R_StoreWallRange
+( int start,
+ int stop );
+
+
+
+
+//
+// R_ClearDrawSegs
+//
+void R_ClearDrawSegs (void)
+{
+ ds_p = drawsegs;
+}
+
+
+
+//
+// ClipWallSegment
+// Clips the given range of columns
+// and includes it in the new clip list.
+//
+typedef struct
+{
+ int first;
+ int last;
+
+} cliprange_t;
+
+
+#define MAXSEGS 32
+
+// newend is one past the last valid seg
+cliprange_t* newend;
+cliprange_t solidsegs[MAXSEGS];
+
+
+
+
+//
+// R_ClipSolidWallSegment
+// Does handle solid walls,
+// e.g. single sided LineDefs (middle texture)
+// that entirely block the view.
+//
+void
+R_ClipSolidWallSegment
+( int first,
+ int last )
+{
+ cliprange_t* next;
+ cliprange_t* start;
+
+ // Find the first range that touches the range
+ // (adjacent pixels are touching).
+ start = solidsegs;
+ while (start->last < first-1)
+ start++;
+
+ if (first < start->first)
+ {
+ if (last < start->first-1)
+ {
+ // Post is entirely visible (above start),
+ // so insert a new clippost.
+ R_StoreWallRange (first, last);
+ next = newend;
+ newend++;
+
+ while (next != start)
+ {
+ *next = *(next-1);
+ next--;
+ }
+ next->first = first;
+ next->last = last;
+ return;
+ }
+
+ // There is a fragment above *start.
+ R_StoreWallRange (first, start->first - 1);
+ // Now adjust the clip size.
+ start->first = first;
+ }
+
+ // Bottom contained in start?
+ if (last <= start->last)
+ return;
+
+ next = start;
+ while (last >= (next+1)->first-1)
+ {
+ // There is a fragment between two posts.
+ R_StoreWallRange (next->last + 1, (next+1)->first - 1);
+ next++;
+
+ if (last <= next->last)
+ {
+ // Bottom is contained in next.
+ // Adjust the clip size.
+ start->last = next->last;
+ goto crunch;
+ }
+ }
+
+ // There is a fragment after *next.
+ R_StoreWallRange (next->last + 1, last);
+ // Adjust the clip size.
+ start->last = last;
+
+ // Remove start+1 to next from the clip list,
+ // because start now covers their area.
+ crunch:
+ if (next == start)
+ {
+ // Post just extended past the bottom of one post.
+ return;
+ }
+
+
+ while (next++ != newend)
+ {
+ // Remove a post.
+ *++start = *next;
+ }
+
+ newend = start+1;
+}
+
+
+
+//
+// R_ClipPassWallSegment
+// Clips the given range of columns,
+// but does not includes it in the clip list.
+// Does handle windows,
+// e.g. LineDefs with upper and lower texture.
+//
+void
+R_ClipPassWallSegment
+( int first,
+ int last )
+{
+ cliprange_t* start;
+
+ // Find the first range that touches the range
+ // (adjacent pixels are touching).
+ start = solidsegs;
+ while (start->last < first-1)
+ start++;
+
+ if (first < start->first)
+ {
+ if (last < start->first-1)
+ {
+ // Post is entirely visible (above start).
+ R_StoreWallRange (first, last);
+ return;
+ }
+
+ // There is a fragment above *start.
+ R_StoreWallRange (first, start->first - 1);
+ }
+
+ // Bottom contained in start?
+ if (last <= start->last)
+ return;
+
+ while (last >= (start+1)->first-1)
+ {
+ // There is a fragment between two posts.
+ R_StoreWallRange (start->last + 1, (start+1)->first - 1);
+ start++;
+
+ if (last <= start->last)
+ return;
+ }
+
+ // There is a fragment after *next.
+ R_StoreWallRange (start->last + 1, last);
+}
+
+
+
+//
+// R_ClearClipSegs
+//
+void R_ClearClipSegs (void)
+{
+ solidsegs[0].first = -0x7fffffff;
+ solidsegs[0].last = -1;
+ solidsegs[1].first = viewwidth;
+ solidsegs[1].last = 0x7fffffff;
+ newend = solidsegs+2;
+}
+
+//
+// R_AddLine
+// Clips the given segment
+// and adds any visible pieces to the line list.
+//
+void R_AddLine (seg_t* line)
+{
+ int x1;
+ int x2;
+ angle_t angle1;
+ angle_t angle2;
+ angle_t span;
+ angle_t tspan;
+
+ curline = line;
+
+ // OPTIMIZE: quickly reject orthogonal back sides.
+ angle1 = R_PointToAngle (line->v1->x, line->v1->y);
+ angle2 = R_PointToAngle (line->v2->x, line->v2->y);
+
+ // Clip to view edges.
+ // OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW).
+ 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;
+ x1 = viewangletox[angle1];
+ x2 = viewangletox[angle2];
+
+ // Does not cross a pixel?
+ if (x1 == x2)
+ return;
+
+ backsector = line->backsector;
+
+ // Single sided line?
+ if (!backsector)
+ goto clipsolid;
+
+ // Closed door.
+ if (backsector->ceilingheight <= frontsector->floorheight
+ || backsector->floorheight >= frontsector->ceilingheight)
+ goto clipsolid;
+
+ // Window.
+ if (backsector->ceilingheight != frontsector->ceilingheight
+ || backsector->floorheight != frontsector->floorheight)
+ goto clippass;
+
+ // 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.
+ if (backsector->ceilingpic == frontsector->ceilingpic
+ && backsector->floorpic == frontsector->floorpic
+ && backsector->lightlevel == frontsector->lightlevel
+ && curline->sidedef->midtexture == 0)
+ {
+ return;
+ }
+
+
+ clippass:
+ R_ClipPassWallSegment (x1, x2-1);
+ return;
+
+ clipsolid:
+ R_ClipSolidWallSegment (x1, x2-1);
+}
+
+
+//
+// R_CheckBBox
+// Checks BSP node/subtree bounding box.
+// Returns true
+// if some part of the bbox might be visible.
+//
+int checkcoord[12][4] =
+{
+ {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}
+};
+
+
+boolean R_CheckBBox (fixed_t* bspcoord)
+{
+ int boxx;
+ int boxy;
+ int boxpos;
+
+ fixed_t x1;
+ fixed_t y1;
+ fixed_t x2;
+ fixed_t y2;
+
+ angle_t angle1;
+ angle_t angle2;
+ angle_t span;
+ angle_t tspan;
+
+ cliprange_t* start;
+
+ int sx1;
+ int sx2;
+
+ // Find the corners of the box
+ // that define the edges from current viewpoint.
+ if (viewx <= bspcoord[BOXLEFT])
+ boxx = 0;
+ else if (viewx < bspcoord[BOXRIGHT])
+ boxx = 1;
+ else
+ boxx = 2;
+
+ if (viewy >= bspcoord[BOXTOP])
+ boxy = 0;
+ else if (viewy > bspcoord[BOXBOTTOM])
+ boxy = 1;
+ else
+ boxy = 2;
+
+ boxpos = (boxy<<2)+boxx;
+ if (boxpos == 5)
+ return true;
+
+ x1 = bspcoord[checkcoord[boxpos][0]];
+ y1 = bspcoord[checkcoord[boxpos][1]];
+ x2 = bspcoord[checkcoord[boxpos][2]];
+ y2 = bspcoord[checkcoord[boxpos][3]];
+
+ // check clip list for an open space
+ angle1 = R_PointToAngle (x1, y1) - viewangle;
+ angle2 = R_PointToAngle (x2, y2) - viewangle;
+
+ span = angle1 - angle2;
+
+ // Sitting on a line?
+ if (span >= ANG180)
+ return true;
+
+ tspan = angle1 + clipangle;
+
+ if (tspan > 2*clipangle)
+ {
+ tspan -= 2*clipangle;
+
+ // Totally off the left edge?
+ if (tspan >= span)
+ return false;
+
+ angle1 = clipangle;
+ }
+ tspan = clipangle - angle2;
+ if (tspan > 2*clipangle)
+ {
+ tspan -= 2*clipangle;
+
+ // Totally off the left edge?
+ if (tspan >= span)
+ return false;
+
+ angle2 = 0 - clipangle;
+ }
+
+
+ // Find the first clippost
+ // that touches the source post
+ // (adjacent pixels are touching).
+ angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
+ angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
+ sx1 = viewangletox[angle1];
+ sx2 = viewangletox[angle2];
+
+ // Does not cross a pixel.
+ if (sx1 == sx2)
+ return false;
+ sx2--;
+
+ start = solidsegs;
+ while (start->last < sx2)
+ start++;
+
+ if (sx1 >= start->first
+ && sx2 <= start->last)
+ {
+ // The clippost contains the new span.
+ return false;
+ }
+
+ return true;
+}
+
+
+
+//
+// R_Subsector
+// Determine floor/ceiling planes.
+// Add sprites of things in sector.
+// Draw one or more line segments.
+//
+void R_Subsector (int num)
+{
+ int count;
+ seg_t* line;
+ subsector_t* sub;
+
+#ifdef RANGECHECK
+ if (num>=numsubsectors)
+ I_Error ("R_Subsector: ss %i with numss = %i",
+ num,
+ numsubsectors);
+#endif
+
+ sscount++;
+ sub = &subsectors[num];
+ frontsector = sub->sector;
+ count = sub->numlines;
+ line = &segs[sub->firstline];
+
+ if (frontsector->floorheight < viewz)
+ {
+ floorplane = R_FindPlane (frontsector->floorheight,
+ frontsector->floorpic,
+ frontsector->lightlevel);
+ }
+ else
+ floorplane = NULL;
+
+ if (frontsector->ceilingheight > viewz
+ || frontsector->ceilingpic == skyflatnum)
+ {
+ ceilingplane = R_FindPlane (frontsector->ceilingheight,
+ frontsector->ceilingpic,
+ frontsector->lightlevel);
+ }
+ else
+ ceilingplane = NULL;
+
+ R_AddSprites (frontsector);
+
+ while (count--)
+ {
+ R_AddLine (line);
+ line++;
+ }
+}
+
+
+
+
+//
+// RenderBSPNode
+// Renders all subsectors below a given node,
+// traversing subtree recursively.
+// Just call with BSP root.
+void R_RenderBSPNode (int bspnum)
+{
+ node_t* bsp;
+ int side;
+
+ // Found a subsector?
+ if (bspnum & NF_SUBSECTOR)
+ {
+ if (bspnum == -1)
+ R_Subsector (0);
+ else
+ R_Subsector (bspnum&(~NF_SUBSECTOR));
+ return;
+ }
+
+ bsp = &nodes[bspnum];
+
+ // Decide which side the view point is on.
+ 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]))
+ R_RenderBSPNode (bsp->children[side^1]);
+}
+
+
diff --git a/src/strife/r_bsp.h b/src/strife/r_bsp.h
new file mode 100644
index 00000000..284f9cf6
--- /dev/null
+++ b/src/strife/r_bsp.h
@@ -0,0 +1,69 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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__
+
+
+
+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;
+
+// false if the back side is the same plane
+extern boolean markfloor;
+extern boolean markceiling;
+
+extern boolean skymap;
+
+extern drawseg_t drawsegs[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);
+
+
+#endif
diff --git a/src/strife/r_data.c b/src/strife/r_data.c
new file mode 100644
index 00000000..b8fa5686
--- /dev/null
+++ b/src/strife/r_data.c
@@ -0,0 +1,1026 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+
+#include "d_main.h"
+#include "deh_main.h"
+#include "i_swap.h"
+#include "i_system.h"
+#include "z_zone.h"
+#include "w_wad.h"
+#include "doomdef.h"
+#include "r_local.h"
+#include "p_local.h"
+#include "doomstat.h"
+#include "r_sky.h"
+#include "r_data.h"
+#include "sounds.h" // villsa [STRIFE]
+
+//
+// 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; // villsa [STRIFE] removed
+ //short colormap; // villsa [STRIFE] removed
+} PACKEDATTR mappatch_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];
+ int masked;
+ short width;
+ short height;
+ //int obsolete; // villsa [STRIFE] removed
+ short patchcount;
+ mappatch_t patches[1];
+} PACKEDATTR maptexture_t;
+
+
+// A single patch from a texture definition,
+// basically a rectangular area within
+// the texture rectangle.
+typedef struct
+{
+ // Block origin (allways UL),
+ // which has allready accounted
+ // for the internal origin of the patch.
+ short originx;
+ short originy;
+ int patch;
+} texpatch_t;
+
+
+// A maptexturedef_t describes a rectangular texture,
+// which is composed of one or more mappatch_t structures
+// that arrange graphic patches.
+
+typedef struct texture_s texture_t;
+
+struct texture_s
+{
+ // Keep name for switch changing, etc.
+ char name[8];
+ short width;
+ short height;
+
+ // Index in textures list
+
+ int index;
+
+ // Next in hash table chain
+
+ texture_t *next;
+
+ // All the patches[patchcount]
+ // are drawn back to front into the cached texture.
+ short patchcount;
+ texpatch_t patches[1];
+};
+
+
+
+int firstflat;
+int lastflat;
+int numflats;
+
+int firstpatch;
+int lastpatch;
+int numpatches;
+
+int firstspritelump;
+int lastspritelump;
+int numspritelumps;
+
+int numtextures;
+texture_t** textures;
+texture_t** textures_hashtable;
+
+
+int* texturewidthmask;
+// needed for texture pegging
+fixed_t* textureheight;
+int* texturecompositesize;
+short** texturecolumnlump;
+unsigned short** texturecolumnofs;
+byte** texturecomposite;
+
+// for global animation
+int* flattranslation;
+int* texturetranslation;
+
+// needed for pre rendering
+fixed_t* spritewidth;
+fixed_t* spriteoffset;
+fixed_t* spritetopoffset;
+
+lighttable_t *colormaps;
+
+
+//
+// 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.
+//
+void
+R_DrawColumnInCache
+( column_t* patch,
+ byte* cache,
+ int originy,
+ int cacheheight )
+{
+ int count;
+ int position;
+ byte* source;
+
+ while (patch->topdelta != 0xff)
+ {
+ source = (byte *)patch + 3;
+ count = patch->length;
+ position = originy + patch->topdelta;
+
+ if (position < 0)
+ {
+ count += position;
+ position = 0;
+ }
+
+ if (position + count > cacheheight)
+ count = cacheheight - position;
+
+ if (count > 0)
+ memcpy (cache + position, source, 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.
+//
+void R_GenerateComposite (int texnum)
+{
+ byte* block;
+ texture_t* texture;
+ texpatch_t* patch;
+ patch_t* realpatch;
+ int x;
+ int x1;
+ int x2;
+ int i;
+ column_t* patchcol;
+ short* collump;
+ unsigned short* colofs;
+
+ texture = textures[texnum];
+
+ block = Z_Malloc (texturecompositesize[texnum],
+ PU_STATIC,
+ &texturecomposite[texnum]);
+
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+ // Composite the columns together.
+ patch = texture->patches;
+
+ for (i=0 , patch = texture->patches;
+ i<texture->patchcount;
+ i++, patch++)
+ {
+ realpatch = W_CacheLumpNum (patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+
+ if (x1<0)
+ x = 0;
+ else
+ x = x1;
+
+ if (x2 > texture->width)
+ x2 = texture->width;
+
+ for ( ; x<x2 ; x++)
+ {
+ // Column does not have multiple patches?
+ if (collump[x] >= 0)
+ continue;
+
+ patchcol = (column_t *)((byte *)realpatch
+ + LONG(realpatch->columnofs[x-x1]));
+ R_DrawColumnInCache (patchcol,
+ block + colofs[x],
+ patch->originy,
+ texture->height);
+ }
+
+ }
+
+ // Now that the texture has been built in column cache,
+ // it is purgable from zone memory.
+ Z_ChangeTag (block, PU_CACHE);
+}
+
+
+
+//
+// R_GenerateLookup
+//
+void R_GenerateLookup (int texnum)
+{
+ texture_t* texture;
+ byte* patchcount; // patchcount[texture->width]
+ texpatch_t* patch;
+ patch_t* realpatch;
+ int x;
+ int x1;
+ int x2;
+ int i;
+ short* collump;
+ unsigned short* colofs;
+
+ texture = textures[texnum];
+
+ // Composited texture not created yet.
+ texturecomposite[texnum] = 0;
+
+ texturecompositesize[texnum] = 0;
+ collump = texturecolumnlump[texnum];
+ colofs = texturecolumnofs[texnum];
+
+ // 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.
+ patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount);
+ memset (patchcount, 0, texture->width);
+ patch = texture->patches;
+
+ for (i=0 , patch = texture->patches;
+ i<texture->patchcount;
+ i++, patch++)
+ {
+ realpatch = W_CacheLumpNum (patch->patch, PU_CACHE);
+ x1 = patch->originx;
+ x2 = x1 + SHORT(realpatch->width);
+
+ if (x1 < 0)
+ x = 0;
+ else
+ x = x1;
+
+ if (x2 > texture->width)
+ x2 = texture->width;
+ for ( ; x<x2 ; x++)
+ {
+ patchcount[x]++;
+ collump[x] = patch->patch;
+ colofs[x] = LONG(realpatch->columnofs[x-x1])+3;
+ }
+ }
+
+ for (x=0 ; x<texture->width ; x++)
+ {
+ if (!patchcount[x])
+ {
+ printf ("R_GenerateLookup: column without a patch (%s)\n",
+ texture->name);
+ return;
+ }
+ // I_Error ("R_GenerateLookup: column without a patch");
+
+ if (patchcount[x] > 1)
+ {
+ // Use the cached block.
+ collump[x] = -1;
+ colofs[x] = texturecompositesize[texnum];
+
+ if (texturecompositesize[texnum] > 0x10000-texture->height)
+ {
+ I_Error ("R_GenerateLookup: texture %i is >64k",
+ texnum);
+ }
+
+ texturecompositesize[texnum] += texture->height;
+ }
+ }
+
+ Z_Free(patchcount);
+}
+
+
+
+
+//
+// R_GetColumn
+//
+byte*
+R_GetColumn
+( int tex,
+ int col )
+{
+ int lump;
+ int ofs;
+
+ col &= texturewidthmask[tex];
+ lump = texturecolumnlump[tex][col];
+ ofs = texturecolumnofs[tex][col];
+
+ if (lump > 0)
+ return (byte *)W_CacheLumpNum(lump,PU_CACHE)+ofs;
+
+ if (!texturecomposite[tex])
+ R_GenerateComposite (tex);
+
+ return texturecomposite[tex] + ofs;
+}
+
+
+static void GenerateTextureHashTable(void)
+{
+ texture_t **rover;
+ int i;
+ int key;
+
+ textures_hashtable
+ = Z_Malloc(sizeof(texture_t *) * numtextures, PU_STATIC, 0);
+
+ memset(textures_hashtable, 0, sizeof(texture_t *) * numtextures);
+
+ // Add all textures to hash table
+
+ for (i=0; i<numtextures; ++i)
+ {
+ // Store index
+
+ textures[i]->index = i;
+
+ // Vanilla Doom does a linear search of the texures array
+ // and stops at the first entry it finds. If there are two
+ // entries with the same name, the first one in the array
+ // wins. The new entry must therefore be added at the end
+ // of the hash chain, so that earlier entries win.
+
+ key = W_LumpNameHash(textures[i]->name) % numtextures;
+
+ rover = &textures_hashtable[key];
+
+ while (*rover != NULL)
+ {
+ rover = &(*rover)->next;
+ }
+
+ // Hook into hash table
+
+ textures[i]->next = NULL;
+ *rover = textures[i];
+ }
+}
+
+
+//
+// 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;
+ int j;
+
+ int* maptex;
+ int* maptex2;
+ int* maptex1;
+
+ char name[9];
+ char* names;
+ char* name_p;
+
+ int* patchlookup;
+
+ int totalwidth;
+ int nummappatches;
+ int offset;
+ int maxoff;
+ int maxoff2;
+ int numtextures1;
+ int numtextures2;
+
+ int* directory;
+
+ int temp1;
+ int temp2;
+ int temp3;
+
+
+ // Load the patch names from pnames.lmp.
+ name[8] = 0;
+ names = W_CacheLumpName (DEH_String("PNAMES"), PU_STATIC);
+ nummappatches = LONG ( *((int *)names) );
+ name_p = names+4;
+ patchlookup = Z_Malloc(nummappatches*sizeof(*patchlookup), PU_STATIC, NULL);
+
+ for (i=0 ; i<nummappatches ; i++)
+ {
+ strncpy (name,name_p+i*8, 8);
+ patchlookup[i] = W_CheckNumForName (name);
+ }
+ W_ReleaseLumpName(DEH_String("PNAMES"));
+
+ // 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_CacheLumpName (DEH_String("TEXTURE1"), PU_STATIC);
+ numtextures1 = LONG(*maptex);
+ maxoff = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE1")));
+ directory = maptex+1;
+
+ if (W_CheckNumForName (DEH_String("TEXTURE2")) != -1)
+ {
+ maptex2 = W_CacheLumpName (DEH_String("TEXTURE2"), PU_STATIC);
+ numtextures2 = LONG(*maptex2);
+ maxoff2 = W_LumpLength (W_GetNumForName (DEH_String("TEXTURE2")));
+ }
+ else
+ {
+ maptex2 = NULL;
+ numtextures2 = 0;
+ maxoff2 = 0;
+ }
+ numtextures = numtextures1 + numtextures2;
+
+ textures = Z_Malloc (numtextures * sizeof(*textures), PU_STATIC, 0);
+ texturecolumnlump = Z_Malloc (numtextures * sizeof(*texturecolumnlump), PU_STATIC, 0);
+ texturecolumnofs = Z_Malloc (numtextures * sizeof(*texturecolumnofs), PU_STATIC, 0);
+ texturecomposite = Z_Malloc (numtextures * sizeof(*texturecomposite), PU_STATIC, 0);
+ texturecompositesize = Z_Malloc (numtextures * sizeof(*texturecompositesize), PU_STATIC, 0);
+ texturewidthmask = Z_Malloc (numtextures * sizeof(*texturewidthmask), PU_STATIC, 0);
+ textureheight = Z_Malloc (numtextures * sizeof(*textureheight), PU_STATIC, 0);
+
+ totalwidth = 0;
+
+ // Really complex printing shit...
+ temp1 = W_GetNumForName (DEH_String("S_START")); // P_???????
+ temp2 = W_GetNumForName (DEH_String("S_END")) - 1;
+ temp3 = ((temp2-temp1+63)/64) + ((numtextures+63)/64);
+
+ // If stdout is a real console, use the classic vanilla "filling
+ // up the box" effect, which uses backspace to "step back" inside
+ // the box. If stdout is a file, don't draw the box.
+
+ // haleyjd 20110206 [STRIFE]: box is in devparm only
+ if (devparm && I_ConsoleStdout())
+ {
+ printf("[");
+ for (i = 0; i < temp3 + 9; i++)
+ printf(" ");
+ printf("]");
+ for (i = 0; i < temp3 + 10; i++)
+ printf("\b");
+ }
+
+ for (i=0 ; i<numtextures ; i++, directory++)
+ {
+ if (!(i&63))
+ {
+ // [STRIFE]: tick intro if not in devparm
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+ }
+
+ 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);
+
+ memcpy (texture->name, mtexture->name, sizeof(texture->name));
+ mpatch = &mtexture->patches[0];
+ patch = &texture->patches[0];
+
+ 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)
+ {
+ I_Error ("R_InitTextures: Missing patch in texture %s",
+ texture->name);
+ }
+ }
+ texturecolumnlump[i] = Z_Malloc (texture->width*sizeof(**texturecolumnlump), PU_STATIC,0);
+ texturecolumnofs[i] = Z_Malloc (texture->width*sizeof(**texturecolumnofs), PU_STATIC,0);
+
+ j = 1;
+ while (j*2 <= texture->width)
+ j<<=1;
+
+ texturewidthmask[i] = j-1;
+ textureheight[i] = texture->height<<FRACBITS;
+
+ totalwidth += texture->width;
+ }
+
+ Z_Free(patchlookup);
+
+ W_ReleaseLumpName(DEH_String("TEXTURE1"));
+ if (maptex2)
+ W_ReleaseLumpName(DEH_String("TEXTURE2"));
+
+ // Precalculate whatever possible.
+
+ for (i=0 ; i<numtextures ; i++)
+ {
+ // [STRIFE]: tick intro
+ if(!(i & 63))
+ D_IntroTick();
+ R_GenerateLookup (i);
+ }
+
+ // Create translation table for global animation.
+ texturetranslation = Z_Malloc ((numtextures+1)*sizeof(*texturetranslation), PU_STATIC, 0);
+
+ for (i=0 ; i<numtextures ; i++)
+ texturetranslation[i] = i;
+
+ GenerateTextureHashTable();
+}
+
+
+
+//
+// R_InitFlats
+//
+void R_InitFlats (void)
+{
+ int i;
+
+ firstflat = W_GetNumForName (DEH_String("F_START")) + 1;
+ lastflat = W_GetNumForName (DEH_String("F_END")) - 1;
+ numflats = lastflat - firstflat + 1;
+
+ // Create translation table for global animation.
+ 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;
+ patch_t *patch;
+
+ firstspritelump = W_GetNumForName (DEH_String("S_START")) + 1;
+ lastspritelump = W_GetNumForName (DEH_String("S_END")) - 1;
+
+ numspritelumps = lastspritelump - firstspritelump + 1;
+ 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++)
+ {
+ if(!(i&63))
+ {
+ // [STRIFE] tick intro if not in devparm
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+ }
+
+ patch = W_CacheLumpNum (firstspritelump+i, PU_CACHE);
+ spritewidth[i] = SHORT(patch->width)<<FRACBITS;
+ spriteoffset[i] = SHORT(patch->leftoffset)<<FRACBITS;
+ spritetopoffset[i] = SHORT(patch->topoffset)<<FRACBITS;
+ }
+}
+
+
+
+//
+// R_InitColormaps
+//
+void R_InitColormaps (void)
+{
+ int lump;
+
+ // Load in the light tables, 256 byte align tables.
+ lump = W_GetNumForName(DEH_String("COLORMAP"));
+ colormaps = W_CacheLumpNum(lump, PU_STATIC);
+}
+
+
+
+//
+// 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 ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick(); // [STRIFE] tick intro
+
+ R_InitFlats ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+
+ R_InitSpriteLumps ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+
+ R_InitColormaps ();
+}
+
+
+
+//
+// R_FlatNumForName
+// Retrieval, get a flat number for a flat name.
+//
+int R_FlatNumForName (char* name)
+{
+ int i;
+ char namet[9];
+
+ i = W_CheckNumForName (name);
+
+ if (i == -1)
+ {
+ namet[8] = 0;
+ memcpy (namet, name,8);
+ I_Error ("R_FlatNumForName: %s not found",namet);
+ }
+ return i - firstflat;
+}
+
+
+
+
+//
+// R_CheckTextureNumForName
+// Check whether texture is available.
+// Filter out NoTexture indicator.
+//
+int R_CheckTextureNumForName (char *name)
+{
+ texture_t *texture;
+ int key;
+
+ // "NoTexture" marker.
+ if (name[0] == '-')
+ return 0;
+
+ key = W_LumpNameHash(name) % numtextures;
+
+ texture=textures_hashtable[key];
+
+ while (texture != NULL)
+ {
+ if (!strncasecmp (texture->name, name, 8) )
+ return texture->index;
+
+ texture = texture->next;
+ }
+
+ return -1;
+}
+
+
+
+//
+// R_TextureNumForName
+// Calls R_CheckTextureNumForName,
+// aborts with error message.
+//
+int R_TextureNumForName (char* name)
+{
+ int i;
+
+ i = R_CheckTextureNumForName (name);
+
+ if (i==-1)
+ {
+ I_Error ("R_TextureNumForName: %s not found",
+ name);
+ }
+ return i;
+}
+
+//
+// R_SoundNumForDoor
+//
+// villsa [STRIFE] - new function
+// Set sounds associated with door though why
+// on earth is this function placed here?
+//
+void R_SoundNumForDoor(vldoor_t* door)
+{
+ int i;
+ sector_t *sector;
+ line_t *line;
+ texture_t *texture;
+ char name[8];
+ char c1;
+ char c2;
+
+ // set default sounds
+ door->opensound = sfx_drsmto;
+ door->closesound = sfx_drsmtc;
+
+ for(sector = door->sector, i = 0; i < sector->linecount; i++)
+ {
+ line = sector->lines[i];
+
+ if(!(line->flags & ML_TWOSIDED))
+ continue;
+
+ texture = textures[sides[line->sidenum[0]].toptexture];
+ memcpy(name, texture->name, 8);
+
+ if(strncmp(name, "DOR", 3))
+ continue;
+
+ c1 = name[3];
+ c2 = name[4];
+
+ // S type
+ if(c1 == 'S')
+ {
+ door->opensound = sfx_drston;
+ door->closesound = sfx_drston;
+ return;
+ }
+
+ // M type
+ if(c1 == 'M')
+ {
+ // L subtype
+ if(c2 == 'L')
+ {
+ door->opensound = sfx_drlmto;
+ door->closesound = sfx_drlmtc;
+ }
+ // S subtype
+ else if(c2 == 'S')
+ {
+ door->opensound = sfx_drsmto;
+ door->closesound = sfx_drsmtc;
+ }
+ return;
+ }
+ // W type
+ else if(c1 == 'W')
+ {
+ // L subtype
+ if(c2 == 'L')
+ {
+ door->opensound = sfx_drlwud;
+ door->closesound = sfx_drlwud;
+ }
+ // S subtype
+ else if(c2 == 'S')
+ {
+ door->opensound = sfx_drswud;
+ door->closesound = sfx_drswud;
+ }
+ return;
+ }
+ }
+}
+
+
+
+
+//
+// R_PrecacheLevel
+// Preloads all relevant graphics for the level.
+//
+int flatmemory;
+int texturememory;
+int spritememory;
+
+void R_PrecacheLevel (void)
+{
+ char* flatpresent;
+ char* texturepresent;
+ char* spritepresent;
+
+ int i;
+ int j;
+ int k;
+ int lump;
+
+ texture_t* texture;
+ thinker_t* th;
+ spriteframe_t* sf;
+
+ if (demoplayback)
+ return;
+
+ // Precache flats.
+ flatpresent = Z_Malloc(numflats, PU_STATIC, NULL);
+ memset (flatpresent,0,numflats);
+
+ for (i=0 ; i<numsectors ; i++)
+ {
+ flatpresent[sectors[i].floorpic] = 1;
+ flatpresent[sectors[i].ceilingpic] = 1;
+ }
+
+ flatmemory = 0;
+
+ for (i=0 ; i<numflats ; i++)
+ {
+ if (flatpresent[i])
+ {
+ lump = firstflat + i;
+ flatmemory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump, PU_CACHE);
+ }
+ }
+
+ Z_Free(flatpresent);
+
+ // Precache textures.
+ texturepresent = Z_Malloc(numtextures, PU_STATIC, NULL);
+ memset (texturepresent,0, numtextures);
+
+ for (i=0 ; i<numsides ; i++)
+ {
+ texturepresent[sides[i].toptexture] = 1;
+ texturepresent[sides[i].midtexture] = 1;
+ texturepresent[sides[i].bottomtexture] = 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.
+ texturepresent[skytexture] = 1;
+
+ texturememory = 0;
+ for (i=0 ; i<numtextures ; i++)
+ {
+ if (!texturepresent[i])
+ continue;
+
+ texture = textures[i];
+
+ for (j=0 ; j<texture->patchcount ; j++)
+ {
+ lump = texture->patches[j].patch;
+ texturememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump , PU_CACHE);
+ }
+ }
+
+ Z_Free(texturepresent);
+
+ // Precache sprites.
+ spritepresent = Z_Malloc(numsprites, PU_STATIC, NULL);
+ memset (spritepresent,0, numsprites);
+
+ for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
+ {
+ if (th->function.acp1 == (actionf_p1)P_MobjThinker)
+ spritepresent[((mobj_t *)th)->sprite] = 1;
+ }
+
+ spritememory = 0;
+ for (i=0 ; i<numsprites ; i++)
+ {
+ if (!spritepresent[i])
+ continue;
+
+ for (j=0 ; j<sprites[i].numframes ; j++)
+ {
+ sf = &sprites[i].spriteframes[j];
+ for (k=0 ; k<8 ; k++)
+ {
+ lump = firstspritelump + sf->lump[k];
+ spritememory += lumpinfo[lump].size;
+ W_CacheLumpNum(lump , PU_CACHE);
+ }
+ }
+ }
+
+ Z_Free(spritepresent);
+}
+
+
+
+
diff --git a/src/strife/r_data.h b/src/strife/r_data.h
new file mode 100644
index 00000000..c8d08179
--- /dev/null
+++ b/src/strife/r_data.h
@@ -0,0 +1,61 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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"
+#include "p_spec.h" // villsa [STRIFE]
+
+
+// Retrieve column data for span blitting.
+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 (char* name);
+
+
+// Called by P_Ticker for switches and animations,
+// returns the texture number for the texture name.
+int R_TextureNumForName (char *name);
+int R_CheckTextureNumForName (char *name);
+void R_SoundNumForDoor(vldoor_t* door); // villsa [STRIFE]
+
+#endif
diff --git a/src/strife/r_defs.h b/src/strife/r_defs.h
new file mode 100644
index 00000000..bbd4b211
--- /dev/null
+++ b/src/strife/r_defs.h
@@ -0,0 +1,456 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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/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"
+
+#include "i_video.h"
+
+#include "v_patch.h"
+
+
+
+
+// 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") did.
+//
+typedef struct
+{
+ fixed_t x;
+ fixed_t y;
+
+} vertex_t;
+
+
+// Forward of LineDefs, for Sectors.
+struct line_s;
+
+// Each sector has a degenmobj_t in its center
+// for sound origin purposes.
+// I suppose this does not handle sound from
+// moving objects (doppler), because
+// position is prolly just buffered, not
+// updated.
+typedef struct
+{
+ thinker_t thinker; // not used for anything
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+
+} degenmobj_t;
+
+//
+// The SECTORS record, at runtime.
+// Stores things/mobjs.
+//
+typedef struct
+{
+ fixed_t floorheight;
+ fixed_t ceilingheight;
+ short floorpic;
+ short ceilingpic;
+ short lightlevel;
+ short special;
+ short tag;
+
+ // 0 = untraversed, 1,2 = sndlines -1
+ int soundtraversed;
+
+ // thing that made a sound (or null)
+ mobj_t* soundtarget;
+
+ // mapblock bounding box for height changes
+ int blockbox[4];
+
+ // origin for any sounds played by the sector
+ degenmobj_t soundorg;
+
+ // if == validcount, already checked
+ int validcount;
+
+ // list of mobjs in sector
+ mobj_t* thinglist;
+
+ // thinker_t for reversable actions
+ void* specialdata;
+
+ int linecount;
+ struct line_s** lines; // [linecount] size
+
+} sector_t;
+
+
+
+
+//
+// The SideDef.
+//
+
+typedef struct
+{
+ // add this to the calculated texture column
+ fixed_t textureoffset;
+
+ // add this to the calculated texture top
+ fixed_t rowoffset;
+
+ // Texture indices.
+ // We do not maintain names here.
+ short toptexture;
+ short bottomtexture;
+ short midtexture;
+
+ // Sector the SideDef is facing.
+ sector_t* sector;
+
+} side_t;
+
+
+
+//
+// Move clipping aid for LineDefs.
+//
+typedef enum
+{
+ ST_HORIZONTAL,
+ ST_VERTICAL,
+ ST_POSITIVE,
+ ST_NEGATIVE
+
+} slopetype_t;
+
+
+
+typedef struct line_s
+{
+ // Vertices, from v1 to v2.
+ vertex_t* v1;
+ vertex_t* v2;
+
+ // Precalculated v2 - v1 for side checking.
+ fixed_t dx;
+ fixed_t dy;
+
+ // Animation related.
+ short flags;
+ short special;
+ short tag;
+
+ // Visual appearance: SideDefs.
+ // sidenum[1] will be -1 if one sided
+ short sidenum[2];
+
+ // Neat. Another bounding box, for the extent
+ // of the LineDef.
+ fixed_t bbox[4];
+
+ // To aid move clipping.
+ slopetype_t slopetype;
+
+ // Front and back sector.
+ // Note: redundant? Can be retrieved from SideDefs.
+ sector_t* frontsector;
+ sector_t* backsector;
+
+ // if == validcount, already checked
+ int validcount;
+
+ // thinker_t for reversable actions
+ void* specialdata;
+} line_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;
+ short numlines;
+ short firstline;
+
+} subsector_t;
+
+
+
+//
+// The LineSeg.
+//
+typedef struct
+{
+ vertex_t* v1;
+ vertex_t* v2;
+
+ fixed_t offset;
+
+ angle_t angle;
+
+ side_t* sidedef;
+ line_t* linedef;
+
+ // Sector references.
+ // Could be retrieved from linedef, too.
+ // backsector is NULL for one sided lines
+ sector_t* frontsector;
+ sector_t* backsector;
+
+} seg_t;
+
+
+
+//
+// BSP node.
+//
+typedef struct
+{
+ // Partition line.
+ fixed_t x;
+ fixed_t y;
+ fixed_t dx;
+ fixed_t dy;
+
+ // Bounding box for each child.
+ fixed_t bbox[2][4];
+
+ // If NF_SUBSECTOR its a subsector.
+ unsigned short children[2];
+
+} node_t;
+
+
+
+
+// PC direct to screen pointers
+//B UNUSED - keep till detailshift in r_draw.c resolved
+//extern byte* destview;
+//extern byte* destscreen;
+
+
+
+
+
+//
+// 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;
+
+
+
+
+//
+// ?
+//
+typedef struct drawseg_s
+{
+ seg_t* curline;
+ int x1;
+ int x2;
+
+ fixed_t scale1;
+ fixed_t scale2;
+ fixed_t scalestep;
+
+ // 0=none, 1=bottom, 2=top, 3=both
+ int silhouette;
+
+ // do not clip sprites above this
+ fixed_t bsilheight;
+
+ // do not clip sprites below this
+ fixed_t tsilheight;
+
+ // Pointers to lists for sprite clipping,
+ // all three adjusted so [x1] is first value.
+ short* sprtopclip;
+ short* sprbottomclip;
+ short* maskedtexturecol;
+
+} drawseg_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
+{
+ // Doubly linked list.
+ struct vissprite_s* prev;
+ struct vissprite_s* next;
+
+ int x1;
+ int x2;
+
+ // for line side calculation
+ fixed_t gx;
+ fixed_t gy;
+
+ // global bottom / top for silhouette clipping
+ fixed_t gz;
+ fixed_t gzt;
+
+ // horizontal position of x1
+ fixed_t startfrac;
+
+ fixed_t scale;
+
+ // negative if flipped
+ fixed_t xiscale;
+
+ fixed_t texturemid;
+ int patch;
+
+ // for color translation and shadow draw,
+ // maxbright frames as well
+ lighttable_t* colormap;
+
+ int mobjflags;
+
+} 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
+{
+ fixed_t height;
+ int picnum;
+ int lightlevel;
+ int minx;
+ int maxx;
+
+ // leave pads for [minx-1]/[maxx+1]
+
+ byte pad1;
+ // Here lies the rub for all
+ // dynamic resize/change of resolution.
+ byte top[SCREENWIDTH];
+ byte pad2;
+ byte pad3;
+ // See above.
+ byte bottom[SCREENWIDTH];
+ byte pad4;
+
+} visplane_t;
+
+
+
+
+#endif
diff --git a/src/strife/r_draw.c b/src/strife/r_draw.c
new file mode 100644
index 00000000..27c44763
--- /dev/null
+++ b/src/strife/r_draw.c
@@ -0,0 +1,976 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 "doomdef.h"
+#include "deh_main.h"
+
+#include "i_system.h"
+#include "z_zone.h"
+#include "w_wad.h"
+
+#include "r_local.h"
+
+// Needs access to LFB (guess what).
+#include "v_video.h"
+
+// State.
+#include "doomstat.h"
+
+
+// ?
+#define MAXWIDTH 1120
+#define MAXHEIGHT 832
+
+// status bar height at bottom of screen
+// haleyjd 08/31/10: Verified unmodified.
+#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* ylookup[MAXHEIGHT];
+int columnofs[MAXWIDTH];
+
+// Color tables for different players,
+// translate a limited part to another
+// (color ramps used for suit colors).
+//
+// [STRIFE] Unused.
+//byte translations[3][256];
+
+// Backing buffer containing the bezel drawn around the screen and
+// surrounding background.
+
+static byte *background_buffer = NULL;
+
+// haleyjd 08/29/10: [STRIFE] Rogue added the ability to customize the view
+// border flat by storing it in the configuration file.
+char *back_flat = "F_PAVE01";
+
+//
+// R_DrawColumn
+// Source is the top of the column to scale.
+//
+lighttable_t* dc_colormap;
+int dc_x;
+int dc_yl;
+int dc_yh;
+fixed_t dc_iscale;
+fixed_t dc_texturemid;
+
+// first pixel in a column (possibly virtual)
+byte* dc_source;
+
+// just for profiling
+int dccount;
+
+//
+// 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;
+ byte* dest;
+ fixed_t frac;
+ fixed_t fracstep;
+
+ 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: %i to %i at %i", dc_yl, dc_yh, dc_x);
+#endif
+
+ // Framebuffer destination address.
+ // Use ylookup LUT to avoid multiply with ScreenWidth.
+ // Use columnofs LUT for subwindows?
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ // Determine scaling,
+ // which is the only mapping to be done.
+ 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.
+ do
+ {
+ // Re-map color indices from wall texture column
+ // using a lighting/special effects LUT.
+ *dest = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
+
+ dest += SCREENWIDTH;
+ frac += fracstep;
+
+ } while (count--);
+}
+
+
+
+// UNUSED.
+// Loop unrolled.
+#if 0
+void R_DrawColumn (void)
+{
+ int count;
+ byte* source;
+ byte* dest;
+ byte* colormap;
+
+ unsigned frac;
+ unsigned fracstep;
+ unsigned fracstep2;
+ unsigned fracstep3;
+ unsigned fracstep4;
+
+ count = dc_yh - dc_yl + 1;
+
+ source = dc_source;
+ colormap = dc_colormap;
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ fracstep = dc_iscale<<9;
+ frac = (dc_texturemid + (dc_yl-centery)*dc_iscale)<<9;
+
+ fracstep2 = fracstep+fracstep;
+ fracstep3 = fracstep2+fracstep;
+ fracstep4 = fracstep3+fracstep;
+
+ while (count >= 8)
+ {
+ dest[0] = colormap[source[frac>>25]];
+ dest[SCREENWIDTH] = colormap[source[(frac+fracstep)>>25]];
+ dest[SCREENWIDTH*2] = colormap[source[(frac+fracstep2)>>25]];
+ dest[SCREENWIDTH*3] = colormap[source[(frac+fracstep3)>>25]];
+
+ frac += fracstep4;
+
+ dest[SCREENWIDTH*4] = colormap[source[frac>>25]];
+ dest[SCREENWIDTH*5] = colormap[source[(frac+fracstep)>>25]];
+ dest[SCREENWIDTH*6] = colormap[source[(frac+fracstep2)>>25]];
+ dest[SCREENWIDTH*7] = colormap[source[(frac+fracstep3)>>25]];
+
+ frac += fracstep4;
+ dest += SCREENWIDTH*8;
+ count -= 8;
+ }
+
+ while (count > 0)
+ {
+ *dest = colormap[source[frac>>25]];
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ count--;
+ }
+}
+#endif
+
+// haleyjd 09/06/10 [STRIFE] Removed low detail
+
+//
+// Spectre/Invisibility.
+//
+
+// haleyjd 09/06/10: ]STRIFE] replaced fuzzdraw with translucency.
+
+//
+// R_DrawMVisTLColumn
+//
+// villsa [STRIFE] new function
+// Replacement for R_DrawFuzzColumn
+//
+void R_DrawMVisTLColumn(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 >= SCREENWIDTH
+ || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ {
+ I_Error ("R_DrawFuzzColumn: %i to %i at %i",
+ dc_yl, dc_yh, dc_x);
+ }
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ // Looks familiar.
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+ do
+ {
+ byte src = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
+ byte col = xlatab[*dest + (src << 8)];
+ *dest = col;
+ dest += SCREENWIDTH;
+ frac += fracstep;
+ } while(count--);
+}
+
+//
+// R_DrawTLColumn
+//
+// villsa [STRIFE] new function
+// Achieves a second translucency level using the same lookup table,
+// via inversion of the colors in the index computation.
+//
+void R_DrawTLColumn(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 >= SCREENWIDTH
+ || dc_yl < 0 || dc_yh >= SCREENHEIGHT)
+ {
+ I_Error ("R_DrawFuzzColumn2: %i to %i at %i",
+ dc_yl, dc_yh, dc_x);
+ }
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ // Looks familiar.
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+ do
+ {
+ byte src = dc_colormap[dc_source[(frac>>FRACBITS)&127]];
+ byte col = xlatab[(*dest << 8) + src];
+ *dest = col;
+ 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;
+byte* 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 >= SCREENWIDTH
+ || dc_yl < 0
+ || dc_yh >= SCREENHEIGHT)
+ {
+ I_Error ( "R_DrawColumn: %i to %i at %i",
+ dc_yl, dc_yh, dc_x);
+ }
+
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[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--);
+}
+
+// haleyjd 09/06/10 [STRIFE] Removed low detail
+
+//
+// R_DrawTRTLColumn
+//
+// villsa [STRIFE] new function
+// Combines translucency and color translation.
+//
+void R_DrawTRTLColumn(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 >= SCREENWIDTH
+ || dc_yl < 0
+ || dc_yh >= SCREENHEIGHT)
+ {
+ I_Error ( "R_DrawColumn: %i to %i at %i",
+ dc_yl, dc_yh, dc_x);
+ }
+#endif
+
+ dest = ylookup[dc_yl] + columnofs[dc_x];
+
+ // Looks familiar.
+ fracstep = dc_iscale;
+ frac = dc_texturemid + (dc_yl-centery)*fracstep;
+
+ // Here we do an additional index re-mapping.
+ do
+ {
+ byte src = dc_colormap[dc_translation[dc_source[frac>>FRACBITS&127]]];
+ byte col = xlatab[(*dest << 8) + src];
+ *dest = col;
+ 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.
+//
+// haleyjd 08/26/10: [STRIFE]
+// * Added loading of XLATAB
+//
+void R_InitTranslationTables (void)
+{
+ int i;
+ byte col1, col2;
+
+ // [STRIFE] Load xlatab. Here's how Rogue did it:
+ // v7 = W_CacheLumpName("XLATAB", PU_CACHE); // note potential cache bug...
+ // HIWORD(v8) = (Z_Malloc(131072, PU_STATIC, NULL) + 65535) >> 16;
+ // LOWORD(v8) = 0; // aligning to a 64K boundary, as if this is Wolf3D.
+ // xlatab = v8;
+ // memcpy(v8, v7, 65536);
+ // As you can see, they copypasta'd id's unnecessary 64K boundary alignment
+ // from the colormap code. Since this doesn't accomplish anything, and isn't
+ // strictly portable, all we need to do is this:
+
+ // villsa [STRIFE] 09/26/10: load table through this function instead
+ V_LoadXlaTable();
+
+ // villsa [STRIFE] allocate a larger size for translation tables
+ translationtables = Z_Malloc (256*8, PU_STATIC, 0);
+
+ col1 = 0xFA;
+ col2 = 0xE0;
+
+ // villsa [STRIFE] setup all translation tables
+ for(i = 0; i < 256; i++)
+ {
+ if(i >= 0x80 && i <= 0x8f)
+ {
+ translationtables [i ] = (i & 0x0f) + 64;
+ translationtables [i+ 256] = (i & 0x0f) - 80;
+ translationtables [i+2*256] = (i & 0x0f) + 16;
+ translationtables [i+3*256] = (i & 0x0f) + 48;
+ translationtables [i+4*256] = (i & 0x0f) + 80;
+ translationtables [i+5*256] = (i & 0x0f) + 96;
+ translationtables [i+6*256] = (i & 0x0f) - 112;
+ }
+ else if(i >= 0x50 && i<= 0x5f)
+ {
+ translationtables [i ] = i;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = (i & 0x0f) + 0x80;
+ translationtables [i+5*256] = (i & 0x0f) + 16;
+ translationtables [i+6*256] = (i & 0x0f) + 64;
+ }
+ else if(i >= 0xd0 && i<= 0xdf)
+ {
+ translationtables [i ] = i;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = (i & 0x0f) - 80;
+ translationtables [i+5*256] = (i & 0x0f) + 48;
+ translationtables [i+6*256] = (i & 0x0f) + 16;
+ }
+ else if(i >= 0xc0 && i<= 0xcf)
+ {
+ translationtables [i ] = i;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = (i & 0x0f) - 96;
+ translationtables [i+5*256] = (i & 0x0f) + 32;
+ translationtables [i+6*256] = (i & 0x0f);
+ // haleyjd 20110213: missing code:
+ if(!(i & 0x0f))
+ translationtables[i+6*256] = 1;
+ }
+ else if(i >= 0xf7 && i<= 0xfb)
+ {
+ translationtables [i ] = col1;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = i;
+ translationtables [i+5*256] = i;
+ translationtables [i+6*256] = i;
+ }
+ else if(i >= 0xf1 && i<= 0xf6)
+ {
+ translationtables [i ] = (i & 0x0f) - 33;
+ translationtables [i+ 256] = i;
+ translationtables [i+2*256] = i;
+ translationtables [i+3*256] = i;
+ translationtables [i+4*256] = i;
+ translationtables [i+5*256] = i;
+ translationtables [i+6*256] = i;
+ }
+ else if(i >= 0x20 && i <= 0x3f) // haleyjd 20110213: fixed upper end
+ {
+ translationtables [i ] = col2;
+ translationtables [i+ 256] = col2;
+ translationtables [i+2*256] = (i & 0x0f) - 48;
+ translationtables [i+3*256] = (i & 0x0f) - 48;
+ translationtables [i+4*256] = col2;
+ translationtables [i+5*256] = col2;
+ translationtables [i+6*256] = col2;
+ }
+ else // Keep all other colors as is.
+ {
+ translationtables[i]=
+ translationtables[i+256]=
+ translationtables[i+2*256]=
+ translationtables[i+3*256]=
+ translationtables[i+4*256]=
+ translationtables[i+5*256]=
+ translationtables[i+6*256]=i;
+ }
+
+ ++col1;
+ ++col2;
+ }
+}
+
+
+
+
+//
+// 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;
+int ds_x1;
+int ds_x2;
+
+lighttable_t* ds_colormap;
+
+fixed_t ds_xfrac;
+fixed_t ds_yfrac;
+fixed_t ds_xstep;
+fixed_t ds_ystep;
+
+// start of a 64*64 tile image
+byte* ds_source;
+
+// just for profiling
+int dscount;
+
+
+//
+// Draws the actual span.
+void R_DrawSpan (void)
+{
+ unsigned int position, step;
+ byte *dest;
+ int count;
+ int spot;
+ unsigned int xtemp, ytemp;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1
+ || ds_x1<0
+ || ds_x2>=SCREENWIDTH
+ || (unsigned)ds_y>SCREENHEIGHT)
+ {
+ I_Error( "R_DrawSpan: %i to %i at %i",
+ ds_x1,ds_x2,ds_y);
+ }
+// dscount++;
+#endif
+
+ // Pack position and step variables into a single 32-bit integer,
+ // with x in the top 16 bits and y in the bottom 16 bits. For
+ // each 16-bit part, the top 6 bits are the integer part and the
+ // bottom 10 bits are the fractional part of the pixel position.
+
+ position = ((ds_xfrac << 10) & 0xffff0000)
+ | ((ds_yfrac >> 6) & 0x0000ffff);
+ step = ((ds_xstep << 10) & 0xffff0000)
+ | ((ds_ystep >> 6) & 0x0000ffff);
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+
+ // We do not check for zero spans here?
+ count = ds_x2 - ds_x1;
+
+ do
+ {
+ // Calculate current texture index in u,v.
+ ytemp = (position >> 4) & 0x0fc0;
+ xtemp = (position >> 26);
+ spot = xtemp | ytemp;
+
+ // Lookup pixel from flat texture tile,
+ // re-index using light/colormap.
+ *dest++ = ds_colormap[ds_source[spot]];
+
+ position += step;
+
+ } while (count--);
+}
+
+
+
+// UNUSED.
+// Loop unrolled by 4.
+#if 0
+void R_DrawSpan (void)
+{
+ unsigned position, step;
+
+ byte* source;
+ byte* colormap;
+ byte* dest;
+
+ unsigned count;
+ usingned spot;
+ unsigned value;
+ unsigned temp;
+ unsigned xtemp;
+ unsigned ytemp;
+
+ position = ((ds_xfrac<<10)&0xffff0000) | ((ds_yfrac>>6)&0xffff);
+ step = ((ds_xstep<<10)&0xffff0000) | ((ds_ystep>>6)&0xffff);
+
+ source = ds_source;
+ colormap = ds_colormap;
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+ count = ds_x2 - ds_x1 + 1;
+
+ while (count >= 4)
+ {
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ dest[0] = colormap[source[spot]];
+
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ dest[1] = colormap[source[spot]];
+
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ dest[2] = colormap[source[spot]];
+
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ dest[3] = colormap[source[spot]];
+
+ count -= 4;
+ dest += 4;
+ }
+ while (count > 0)
+ {
+ ytemp = position>>4;
+ ytemp = ytemp & 4032;
+ xtemp = position>>26;
+ spot = xtemp | ytemp;
+ position += step;
+ *dest++ = colormap[source[spot]];
+ count--;
+ }
+}
+#endif
+
+
+//
+// Again..
+//
+void R_DrawSpanLow (void)
+{
+ unsigned int position, step;
+ unsigned int xtemp, ytemp;
+ byte *dest;
+ int count;
+ int spot;
+
+#ifdef RANGECHECK
+ if (ds_x2 < ds_x1
+ || ds_x1<0
+ || ds_x2>=SCREENWIDTH
+ || (unsigned)ds_y>SCREENHEIGHT)
+ {
+ I_Error( "R_DrawSpan: %i to %i at %i",
+ ds_x1,ds_x2,ds_y);
+ }
+// dscount++;
+#endif
+
+ position = ((ds_xfrac << 10) & 0xffff0000)
+ | ((ds_yfrac >> 6) & 0x0000ffff);
+ step = ((ds_xstep << 10) & 0xffff0000)
+ | ((ds_ystep >> 6) & 0x0000ffff);
+
+ count = (ds_x2 - ds_x1);
+
+ // Blocky mode, need to multiply by 2.
+ ds_x1 <<= 1;
+ ds_x2 <<= 1;
+
+ dest = ylookup[ds_y] + columnofs[ds_x1];
+
+ do
+ {
+ // Calculate current texture index in u,v.
+ ytemp = (position >> 4) & 0x0fc0;
+ xtemp = (position >> 26);
+ spot = xtemp | ytemp;
+
+ // Lowres/blocky mode does it twice,
+ // while scale is adjusted appropriately.
+ *dest++ = ds_colormap[ds_source[spot]];
+ *dest++ = ds_colormap[ds_source[spot]];
+
+ position += step;
+
+ } while (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;
+
+ // Handle resize,
+ // e.g. smaller view windows
+ // with border and/or status bar.
+ viewwindowx = (SCREENWIDTH-width) >> 1;
+
+ // Column offset. For windows.
+ for (i=0 ; i<width ; i++)
+ columnofs[i] = viewwindowx + i;
+
+ // Samw with base row offset.
+ if (width == SCREENWIDTH)
+ viewwindowy = 0;
+ else
+ viewwindowy = (SCREENHEIGHT-SBARHEIGHT-height) >> 1;
+
+ // Preclaculate all row offsets.
+ for (i=0 ; i<height ; i++)
+ ylookup[i] = I_VideoBuffer + (i+viewwindowy)*SCREENWIDTH;
+}
+
+
+
+
+//
+// R_FillBackScreen
+// Fills the back screen with a pattern
+// for variable screen sizes
+// Also draws a beveled edge.
+//
+// haleyjd 08/29/10: [STRIFE] Added support for configurable back_flat.
+//
+void R_FillBackScreen (void)
+{
+ byte* src;
+ byte* dest;
+ int x;
+ int y;
+ patch_t* patch;
+
+ char *name;
+
+ // If we are running full screen, there is no need to do any of this,
+ // and the background buffer can be freed if it was previously in use.
+
+ if (scaledviewwidth == SCREENWIDTH)
+ {
+ if (background_buffer != NULL)
+ {
+ Z_Free(background_buffer);
+ background_buffer = NULL;
+ }
+
+ return;
+ }
+
+ // Allocate the background buffer if necessary
+
+ if (background_buffer == NULL)
+ {
+ background_buffer = Z_Malloc(SCREENWIDTH * (SCREENHEIGHT - SBARHEIGHT),
+ PU_STATIC, NULL);
+ }
+
+ // haleyjd 08/29/10: [STRIFE] Use configurable back_flat
+ name = back_flat;
+
+ src = W_CacheLumpName(name, PU_CACHE);
+ dest = background_buffer;
+
+ for (y=0 ; y<SCREENHEIGHT-SBARHEIGHT ; y++)
+ {
+ for (x=0 ; x<SCREENWIDTH/64 ; x++)
+ {
+ memcpy (dest, src+((y&63)<<6), 64);
+ dest += 64;
+ }
+
+ if (SCREENWIDTH&63)
+ {
+ memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
+ dest += (SCREENWIDTH&63);
+ }
+ }
+
+ // Draw screen and bezel; this is done to a separate screen buffer.
+
+ V_UseBuffer(background_buffer);
+
+ patch = W_CacheLumpName(DEH_String("brdr_t"),PU_CACHE);
+
+ for (x=0 ; x<scaledviewwidth ; x+=8)
+ V_DrawPatch(viewwindowx+x, viewwindowy-8, patch);
+ patch = W_CacheLumpName(DEH_String("brdr_b"),PU_CACHE);
+
+ for (x=0 ; x<scaledviewwidth ; x+=8)
+ V_DrawPatch(viewwindowx+x, viewwindowy+viewheight, patch);
+ patch = W_CacheLumpName(DEH_String("brdr_l"),PU_CACHE);
+
+ for (y=0 ; y<viewheight ; y+=8)
+ V_DrawPatch(viewwindowx-8, viewwindowy+y, patch);
+ patch = W_CacheLumpName(DEH_String("brdr_r"),PU_CACHE);
+
+ for (y=0 ; y<viewheight ; y+=8)
+ V_DrawPatch(viewwindowx+scaledviewwidth, viewwindowy+y, patch);
+
+ // Draw beveled edge.
+ V_DrawPatch(viewwindowx-8,
+ viewwindowy-8,
+ W_CacheLumpName(DEH_String("brdr_tl"),PU_CACHE));
+
+ V_DrawPatch(viewwindowx+scaledviewwidth,
+ viewwindowy-8,
+ W_CacheLumpName(DEH_String("brdr_tr"),PU_CACHE));
+
+ V_DrawPatch(viewwindowx-8,
+ viewwindowy+viewheight,
+ W_CacheLumpName(DEH_String("brdr_bl"),PU_CACHE));
+
+ V_DrawPatch(viewwindowx+scaledviewwidth,
+ viewwindowy+viewheight,
+ W_CacheLumpName(DEH_String("brdr_br"),PU_CACHE));
+
+ V_RestoreBuffer();
+}
+
+
+//
+// Copy a screen buffer.
+//
+void
+R_VideoErase
+( unsigned ofs,
+ int count )
+{
+ // LFB copy.
+ // This might not be a good idea if memcpy
+ // is not optiomal, e.g. byte by byte on
+ // a 32bit CPU, as GNU GCC/Linux libc did
+ // at one point.
+
+ if (background_buffer != NULL)
+ {
+ memcpy(I_VideoBuffer + ofs, background_buffer + ofs, count);
+ }
+}
+
+
+//
+// R_DrawViewBorder
+// Draws the border around the view
+// for different size windows?
+//
+void R_DrawViewBorder (void)
+{
+ int top;
+ int side;
+ int ofs;
+ int i;
+
+ if (scaledviewwidth == SCREENWIDTH)
+ return;
+
+ top = ((SCREENHEIGHT-SBARHEIGHT)-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;
+ }
+
+ // ?
+ V_MarkRect (0,0,SCREENWIDTH, SCREENHEIGHT-SBARHEIGHT);
+}
+
+
diff --git a/src/strife/r_draw.h b/src/strife/r_draw.h
new file mode 100644
index 00000000..aaa64711
--- /dev/null
+++ b/src/strife/r_draw.h
@@ -0,0 +1,119 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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__
+
+
+
+
+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;
+
+// first pixel in a column
+extern byte* dc_source;
+
+
+// The span blitting interface.
+// Hook in assembler or system specific BLT
+// here.
+void R_DrawColumn (void);
+void R_DrawColumnLow (void);
+
+// The Spectre/Invisibility effect.
+//void R_DrawFuzzColumn (void);
+//void R_DrawFuzzColumnLow (void);
+
+// Draw with color translation tables,
+// for player sprite rendering,
+// Green/Red/Blue/Indigo shirts.
+void R_DrawTranslatedColumn (void);
+void R_DrawTranslatedColumnLow (void);
+
+// villsa [STRIFE] - transclucent rendering
+void R_DrawTLColumn (void);
+void R_DrawMVisTLColumn (void);
+void R_DrawTRTLColumn (void);
+
+void
+R_VideoErase
+( unsigned ofs,
+ int count );
+
+extern int ds_y;
+extern int ds_x1;
+extern int ds_x2;
+
+extern lighttable_t* ds_colormap;
+
+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* translationtables;
+extern byte* dc_translation;
+extern byte* xlatab; // haleyjd 08/26/10: [STRIFE]
+
+extern char *back_flat; // haleyjd 08/29/10: [STRIFE]
+
+// Span blitting for rows, floor/ceiling.
+// No Sepctre effect needed.
+void R_DrawSpan (void);
+
+// Low resolution mode, 160x200?
+void R_DrawSpanLow (void);
+
+
+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);
+
+
+
+#endif
diff --git a/src/strife/r_local.h b/src/strife/r_local.h
new file mode 100644
index 00000000..8b97bdb0
--- /dev/null
+++ b/src/strife/r_local.h
@@ -0,0 +1,53 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 (R_*) module, global header.
+// All the rendering/drawing stuff is here.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __R_LOCAL__
+#define __R_LOCAL__
+
+// Binary Angles, sine/cosine/atan lookups.
+#include "tables.h"
+
+// Screen size related parameters.
+#include "doomdef.h"
+
+// Include the refresh/render data structs.
+#include "r_data.h"
+
+
+
+//
+// Separate header file for each module.
+//
+#include "r_main.h"
+#include "r_bsp.h"
+#include "r_segs.h"
+#include "r_plane.h"
+#include "r_data.h"
+#include "r_things.h"
+#include "r_draw.h"
+
+#endif // __R_LOCAL__
diff --git a/src/strife/r_main.c b/src/strife/r_main.c
new file mode 100644
index 00000000..cf588159
--- /dev/null
+++ b/src/strife/r_main.c
@@ -0,0 +1,953 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdlib.h>
+#include <math.h>
+
+
+#include "doomdef.h"
+#include "doomstat.h" // villsa [STRIFE]
+#include "d_main.h"
+
+#include "m_bbox.h"
+#include "m_menu.h"
+
+#include "r_local.h"
+#include "r_sky.h"
+
+
+
+
+
+// Fineangles in the SCREENWIDTH wide window.
+#define FIELDOFVIEW 2048
+
+
+
+int viewangleoffset;
+
+// increment every time a check is made
+int validcount = 1;
+
+
+lighttable_t* fixedcolormap;
+extern lighttable_t** walllights;
+
+int centerx;
+int centery;
+
+fixed_t centerxfrac;
+fixed_t centeryfrac;
+fixed_t projection;
+
+// just for profiling purposes
+int framecount;
+
+int sscount;
+int linecount;
+int loopcount;
+
+fixed_t viewx;
+fixed_t viewy;
+fixed_t viewz;
+
+int viewpitch; // villsa [STRIFE]
+
+angle_t viewangle;
+
+fixed_t viewcos;
+fixed_t viewsin;
+
+player_t* viewplayer;
+
+// 0 = high, 1 = low
+int detailshift;
+
+//
+// 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];
+
+lighttable_t* scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+lighttable_t* scalelightfixed[MAXLIGHTSCALE];
+lighttable_t* zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+// bumped light from gun blasts
+int extralight;
+
+
+
+void (*colfunc) (void);
+void (*basecolfunc) (void);
+void (*fuzzcolfunc) (void);
+void (*transcolfunc) (void);
+void (*spanfunc) (void);
+
+
+
+//
+// R_AddPointToBox
+// Expand a given bbox
+// so that it encloses a given point.
+//
+void
+R_AddPointToBox
+( int x,
+ int y,
+ fixed_t* box )
+{
+ if (x< box[BOXLEFT])
+ box[BOXLEFT] = x;
+ if (x> box[BOXRIGHT])
+ box[BOXRIGHT] = x;
+ if (y< box[BOXBOTTOM])
+ box[BOXBOTTOM] = y;
+ if (y> box[BOXTOP])
+ box[BOXTOP] = y;
+}
+
+
+//
+// R_PointOnSide
+// Traverse BSP (sub) tree,
+// check point against partition plane.
+// Returns side 0 (front) or 1 (back).
+//
+int
+R_PointOnSide
+( fixed_t x,
+ fixed_t y,
+ node_t* node )
+{
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t left;
+ fixed_t right;
+
+ if (!node->dx)
+ {
+ if (x <= node->x)
+ return node->dy > 0;
+
+ return node->dy < 0;
+ }
+ if (!node->dy)
+ {
+ if (y <= node->y)
+ return node->dx < 0;
+
+ return node->dx > 0;
+ }
+
+ dx = (x - node->x);
+ dy = (y - node->y);
+
+ // Try to quickly decide by looking at sign bits.
+ if ( (node->dy ^ node->dx ^ dx ^ dy)&0x80000000 )
+ {
+ if ( (node->dy ^ dx) & 0x80000000 )
+ {
+ // (left is negative)
+ return 1;
+ }
+ return 0;
+ }
+
+ left = FixedMul ( node->dy>>FRACBITS , dx );
+ right = FixedMul ( dy , node->dx>>FRACBITS );
+
+ if (right < left)
+ {
+ // front side
+ return 0;
+ }
+ // back side
+ return 1;
+}
+
+
+int
+R_PointOnSegSide
+( fixed_t x,
+ fixed_t y,
+ seg_t* line )
+{
+ fixed_t lx;
+ fixed_t ly;
+ fixed_t ldx;
+ fixed_t ldy;
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t left;
+ fixed_t right;
+
+ lx = line->v1->x;
+ ly = line->v1->y;
+
+ ldx = line->v2->x - lx;
+ ldy = line->v2->y - ly;
+
+ if (!ldx)
+ {
+ if (x <= lx)
+ return ldy > 0;
+
+ return ldy < 0;
+ }
+ if (!ldy)
+ {
+ if (y <= ly)
+ return ldx < 0;
+
+ return ldx > 0;
+ }
+
+ dx = (x - lx);
+ dy = (y - ly);
+
+ // Try to quickly decide by looking at sign bits.
+ if ( (ldy ^ ldx ^ dx ^ dy)&0x80000000 )
+ {
+ if ( (ldy ^ dx) & 0x80000000 )
+ {
+ // (left is negative)
+ return 1;
+ }
+ return 0;
+ }
+
+ left = FixedMul ( ldy>>FRACBITS , dx );
+ right = FixedMul ( dy , ldx>>FRACBITS );
+
+ if (right < left)
+ {
+ // front side
+ return 0;
+ }
+ // back side
+ return 1;
+}
+
+
+//
+// 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.
+
+//
+
+
+
+
+angle_t
+R_PointToAngle
+( fixed_t x,
+ fixed_t y )
+{
+ x -= viewx;
+ y -= viewy;
+
+ if ( (!x) && (!y) )
+ return 0;
+
+ if (x>= 0)
+ {
+ // x >=0
+ if (y>= 0)
+ {
+ // y>= 0
+
+ if (x>y)
+ {
+ // octant 0
+ return tantoangle[ SlopeDiv(y,x)];
+ }
+ else
+ {
+ // octant 1
+ return ANG90-1-tantoangle[ SlopeDiv(x,y)];
+ }
+ }
+ else
+ {
+ // y<0
+ y = -y;
+
+ if (x>y)
+ {
+ // octant 8
+ return 0 - tantoangle[SlopeDiv(y,x)];
+ }
+ else
+ {
+ // octant 7
+ return ANG270+tantoangle[ SlopeDiv(x,y)];
+ }
+ }
+ }
+ else
+ {
+ // x<0
+ x = -x;
+
+ if (y>= 0)
+ {
+ // y>= 0
+ if (x>y)
+ {
+ // octant 3
+ return ANG180-1-tantoangle[ SlopeDiv(y,x)];
+ }
+ else
+ {
+ // octant 2
+ return ANG90+ tantoangle[ SlopeDiv(x,y)];
+ }
+ }
+ else
+ {
+ // y<0
+ y = -y;
+
+ if (x>y)
+ {
+ // octant 4
+ return ANG180+tantoangle[ SlopeDiv(y,x)];
+ }
+ else
+ {
+ // octant 5
+ return ANG270-1-tantoangle[ SlopeDiv(x,y)];
+ }
+ }
+ }
+ return 0;
+}
+
+
+angle_t
+R_PointToAngle2
+( fixed_t x1,
+ fixed_t y1,
+ fixed_t x2,
+ fixed_t y2 )
+{
+ viewx = x1;
+ viewy = y1;
+
+ return R_PointToAngle (x2, y2);
+}
+
+
+fixed_t
+R_PointToDist
+( fixed_t x,
+ fixed_t y )
+{
+ int angle;
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t temp;
+ fixed_t dist;
+ fixed_t frac;
+
+ dx = abs(x - viewx);
+ dy = abs(y - viewy);
+
+ if (dy>dx)
+ {
+ temp = dx;
+ dx = dy;
+ dy = temp;
+ }
+
+ // Fix crashes in udm1.wad
+
+ if (dx != 0)
+ {
+ frac = FixedDiv(dy, dx);
+ }
+ else
+ {
+ frac = 0;
+ }
+
+ angle = (tantoangle[frac>>DBITS]+ANG90) >> ANGLETOFINESHIFT;
+
+ // use as cosine
+ dist = FixedDiv (dx, finesine[angle] );
+
+ return dist;
+}
+
+
+
+
+//
+// R_InitPointToAngle
+//
+void R_InitPointToAngle (void)
+{
+ // UNUSED - now getting from tables.c
+#if 0
+ int i;
+ long t;
+ float f;
+//
+// slope (tangent) to angle lookup
+//
+ for (i=0 ; i<=SLOPERANGE ; i++)
+ {
+ f = atan( (float)i/SLOPERANGE )/(3.141592657*2);
+ t = 0xffffffff*f;
+ tantoangle[i] = t;
+ }
+#endif
+}
+
+
+//
+// R_ScaleFromGlobalAngle
+// Returns the texture mapping scale
+// for the current line (horizontal span)
+// at the given angle.
+// rw_distance must be calculated first.
+//
+fixed_t R_ScaleFromGlobalAngle (angle_t visangle)
+{
+ fixed_t scale;
+ angle_t anglea;
+ angle_t angleb;
+ int sinea;
+ int sineb;
+ fixed_t num;
+ int den;
+
+ // UNUSED
+#if 0
+{
+ fixed_t dist;
+ fixed_t z;
+ fixed_t sinv;
+ fixed_t cosv;
+
+ sinv = finesine[(visangle-rw_normalangle)>>ANGLETOFINESHIFT];
+ dist = FixedDiv (rw_distance, sinv);
+ cosv = finecosine[(viewangle-visangle)>>ANGLETOFINESHIFT];
+ z = abs(FixedMul (dist, cosv));
+ scale = FixedDiv(projection, z);
+ return scale;
+}
+#endif
+
+ anglea = ANG90 + (visangle-viewangle);
+ angleb = ANG90 + (visangle-rw_normalangle);
+
+ // both sines are allways positive
+ sinea = finesine[anglea>>ANGLETOFINESHIFT];
+ sineb = finesine[angleb>>ANGLETOFINESHIFT];
+ num = FixedMul(projection,sineb)<<detailshift;
+ den = FixedMul(rw_distance,sinea);
+
+ if (den > num>>16)
+ {
+ scale = FixedDiv (num, den);
+
+ if (scale > 64*FRACUNIT)
+ scale = 64*FRACUNIT;
+ else if (scale < 256)
+ scale = 256;
+ }
+ else
+ scale = 64*FRACUNIT;
+
+ return scale;
+}
+
+
+
+//
+// R_InitTables
+//
+void R_InitTables (void)
+{
+ // UNUSED: now getting from tables.c
+#if 0
+ int i;
+ float a;
+ float fv;
+ int t;
+
+ // viewangle tangent table
+ for (i=0 ; i<FINEANGLES/2 ; i++)
+ {
+ a = (i-FINEANGLES/4+0.5)*PI*2/FINEANGLES;
+ fv = FRACUNIT*tan (a);
+ t = fv;
+ finetangent[i] = t;
+ }
+
+ // finesine table
+ for (i=0 ; i<5*FINEANGLES/4 ; i++)
+ {
+ // OPTIMIZE: mirror...
+ a = (i+0.5)*PI*2/FINEANGLES;
+ t = FRACUNIT*sin (a);
+ finesine[i] = t;
+ }
+#endif
+
+}
+
+
+
+//
+// R_InitTextureMapping
+//
+void R_InitTextureMapping (void)
+{
+ int i;
+ int x;
+ int t;
+ 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++)
+ {
+ 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++)
+ {
+ i = 0;
+ while (viewangletox[i]>x)
+ i++;
+ xtoviewangle[x] = (i<<ANGLETOFINESHIFT)-ANG90;
+ }
+
+ // Take out the fencepost cases from viewangletox.
+ for (i=0 ; i<FINEANGLES/2 ; i++)
+ {
+ t = FixedMul (finetangent[i], focallength);
+ t = centerx - t;
+
+ 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;
+ int j;
+ int level;
+ int startmap;
+ int scale;
+
+ // Calculate the light levels to use
+ // for each level / distance combination.
+ for (i=0 ; i< LIGHTLEVELS ; i++)
+ {
+ startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
+ for (j=0 ; j<MAXLIGHTZ ; j++)
+ {
+ scale = FixedDiv ((SCREENWIDTH/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
+ scale >>= LIGHTSCALESHIFT;
+ level = startmap - scale/DISTMAP;
+
+ if (level < 0)
+ level = 0;
+
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS-1;
+
+ zlight[i][j] = colormaps + level*256;
+ }
+ }
+}
+
+
+
+//
+// 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;
+int setdetail;
+
+
+void
+R_SetViewSize
+( int blocks,
+ int detail )
+{
+ setsizeneeded = true;
+ setblocks = blocks;
+ setdetail = detail;
+}
+
+
+//
+// R_ExecuteSetViewSize
+//
+void R_ExecuteSetViewSize (void)
+{
+ fixed_t cosadj;
+ fixed_t dy;
+ int i;
+ int j;
+ int level;
+ int startmap;
+
+ setsizeneeded = false;
+
+ if (setblocks == 11)
+ {
+ scaledviewwidth = SCREENWIDTH;
+ viewheight = SCREENHEIGHT;
+ }
+ else
+ {
+ scaledviewwidth = setblocks*32;
+ viewheight = (setblocks*168/10)&~7;
+ }
+
+ detailshift = setdetail;
+ viewwidth = scaledviewwidth>>detailshift;
+
+ // villsa [STRIFE] calculate centery from player's pitch
+ centery = (setblocks*players[consoleplayer].pitch);
+ centery = (unsigned int)(centery/10)+viewheight/2;
+
+ centerx = viewwidth/2;
+ centerxfrac = centerx<<FRACBITS;
+ centeryfrac = centery<<FRACBITS;
+ projection = centerxfrac;
+
+ //if (!detailshift) // villsa [STRIFE]
+ {
+ colfunc = basecolfunc = R_DrawColumn;
+ fuzzcolfunc = R_DrawTLColumn; // villsa [STRIFE]
+ transcolfunc = R_DrawTranslatedColumn;
+ spanfunc = R_DrawSpan;
+ }
+ // villsa [STRIFE] unused detail stuff
+ /*else
+ {
+ colfunc = basecolfunc = R_DrawColumnLow;
+ fuzzcolfunc = R_DrawFuzzColumnLow;
+ transcolfunc = R_DrawTranslatedColumnLow;
+ spanfunc = R_DrawSpanLow;
+ }*/
+
+ 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++)
+ {
+ // haleyjd 20120208: [STRIFE] viewheight/2 -> centery, accounts for up/down look
+ dy = ((i - centery)<<FRACBITS) + FRACUNIT/2;
+ dy = abs(dy);
+ yslope[i] = FixedDiv ( (viewwidth<<detailshift)/2*FRACUNIT, dy);
+ }
+
+ for (i=0 ; i<viewwidth ; i++)
+ {
+ cosadj = 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++)
+ {
+ startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
+ for (j=0 ; j<MAXLIGHTSCALE ; j++)
+ {
+ level = startmap - j*SCREENWIDTH/(viewwidth<<detailshift)/DISTMAP;
+
+ if (level < 0)
+ level = 0;
+
+ if (level >= NUMCOLORMAPS)
+ level = NUMCOLORMAPS-1;
+
+ scalelight[i][j] = colormaps + level*256;
+ }
+ }
+}
+
+
+
+//
+// R_Init
+//
+
+
+
+void R_Init (void)
+{
+ R_InitData ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick(); // [STRIFE] tick intro
+
+ R_InitPointToAngle ();
+ if(devparm)
+ printf (".");
+
+ R_InitTables ();
+ // viewwidth / viewheight / detailLevel are set by the defaults
+ if(devparm)
+ printf (".");
+
+ R_SetViewSize (screenblocks, detailLevel);
+ R_InitPlanes ();
+ if(devparm)
+ printf (".");
+
+ R_InitLightTables ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+
+ R_InitSkyMap ();
+ if(!devparm)
+ D_IntroTick();
+
+ R_InitTranslationTables ();
+ if(devparm)
+ printf (".");
+ else
+ D_IntroTick();
+
+ framecount = 0;
+}
+
+
+//
+// R_PointInSubsector
+//
+subsector_t*
+R_PointInSubsector
+( fixed_t x,
+ fixed_t y )
+{
+ node_t* node;
+ int side;
+ int nodenum;
+
+ // single subsector is a special case
+ if (!numnodes)
+ return subsectors;
+
+ nodenum = numnodes-1;
+
+ while (! (nodenum & NF_SUBSECTOR) )
+ {
+ node = &nodes[nodenum];
+ side = R_PointOnSide (x, y, node);
+ nodenum = node->children[side];
+ }
+
+ return &subsectors[nodenum & ~NF_SUBSECTOR];
+}
+
+//
+// R_SetupPitch
+// villsa [STRIFE] new function
+// Calculate centery/centeryfrac for player viewpitch
+//
+
+void R_SetupPitch(player_t* player)
+{
+ int pitchfrac;
+ int i = 0;
+
+ if(viewpitch != player->pitch)
+ {
+ viewpitch = player->pitch;
+ pitchfrac = (setblocks * player->pitch) / 10;
+ centery = pitchfrac + viewheight / 2;
+ centeryfrac = centery << FRACBITS;
+
+ for(i = 0; i < viewheight; i++)
+ {
+ yslope[i] = FixedDiv(viewwidth / 2 * FRACUNIT,
+ abs(((i - centery) << FRACBITS) + (FRACUNIT/2)));
+ }
+ }
+}
+
+
+//
+// R_SetupFrame
+//
+void R_SetupFrame (player_t* player)
+{
+ int i;
+
+ R_SetupPitch(player); // villsa [STRIFE]
+
+ 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];
+
+ sscount = 0;
+
+ if (player->fixedcolormap)
+ {
+ fixedcolormap =
+ colormaps
+ + player->fixedcolormap*256*sizeof(lighttable_t);
+
+ walllights = scalelightfixed;
+
+ for (i=0 ; i<MAXLIGHTSCALE ; i++)
+ scalelightfixed[i] = fixedcolormap;
+ }
+ else
+ fixedcolormap = 0;
+
+ framecount++;
+ 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/src/strife/r_main.h b/src/strife/r_main.h
new file mode 100644
index 00000000..5cb858bb
--- /dev/null
+++ b/src/strife/r_main.h
@@ -0,0 +1,168 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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_MAIN__
+#define __R_MAIN__
+
+#include "d_player.h"
+#include "r_data.h"
+
+
+
+
+//
+// POV related.
+//
+extern fixed_t viewcos;
+extern fixed_t viewsin;
+
+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;
+
+
+//
+// Lighting LUT.
+// Used for z-depth cuing per column/row,
+// and other lighting effects (sector ambient, flash).
+//
+
+// Lighting constants.
+// Now why not 32 levels here?
+#define LIGHTLEVELS 16
+#define LIGHTSEGSHIFT 4
+
+#define MAXLIGHTSCALE 48
+#define LIGHTSCALESHIFT 12
+#define MAXLIGHTZ 128
+#define LIGHTZSHIFT 20
+
+extern lighttable_t* scalelight[LIGHTLEVELS][MAXLIGHTSCALE];
+extern lighttable_t* scalelightfixed[MAXLIGHTSCALE];
+extern lighttable_t* zlight[LIGHTLEVELS][MAXLIGHTZ];
+
+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
+
+
+// Blocky/low detail mode.
+//B remove this?
+// 0 = high, 1 = low
+extern int detailshift;
+
+
+//
+// Function pointers to switch refresh/drawing functions.
+// Used to select shadow mode etc.
+//
+extern void (*colfunc) (void);
+extern void (*transcolfunc) (void);
+extern void (*basecolfunc) (void);
+extern void (*fuzzcolfunc) (void);
+// No shadow effects on floors.
+extern void (*spanfunc) (void);
+
+
+//
+// Utility functions.
+int
+R_PointOnSide
+( fixed_t x,
+ fixed_t y,
+ node_t* node );
+
+int
+R_PointOnSegSide
+( fixed_t x,
+ fixed_t y,
+ 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 );
+
+fixed_t
+R_PointToDist
+( fixed_t x,
+ fixed_t y );
+
+
+fixed_t R_ScaleFromGlobalAngle (angle_t visangle);
+
+subsector_t*
+R_PointInSubsector
+( fixed_t x,
+ fixed_t y );
+
+void
+R_AddPointToBox
+( int x,
+ int y,
+ fixed_t* box );
+
+
+
+//
+// REFRESH - the actual rendering functions.
+//
+
+// Called by G_Drawer.
+void R_RenderPlayerView (player_t *player);
+
+// Called by startup code.
+void R_Init (void);
+
+// Called by M_Responder.
+void R_SetViewSize (int blocks, int detail);
+
+#endif
diff --git a/src/strife/r_plane.c b/src/strife/r_plane.c
new file mode 100644
index 00000000..fce321f0
--- /dev/null
+++ b/src/strife/r_plane.c
@@ -0,0 +1,455 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "i_system.h"
+#include "z_zone.h"
+#include "w_wad.h"
+
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "r_local.h"
+#include "r_sky.h"
+
+
+
+planefunction_t floorfunc;
+planefunction_t ceilingfunc;
+
+//
+// opening
+//
+
+// Here comes the obnoxious "visplane".
+// haleyjd 08/29/10: [STRIFE] MAXVISPLANES increased to 200
+#define MAXVISPLANES 200
+visplane_t visplanes[MAXVISPLANES];
+visplane_t* lastvisplane;
+visplane_t* floorplane;
+visplane_t* ceilingplane;
+
+// ?
+#define MAXOPENINGS SCREENWIDTH*64
+short openings[MAXOPENINGS];
+short* lastopening;
+
+
+//
+// Clip values are the solid pixel bounding the range.
+// floorclip starts out SCREENHEIGHT
+// ceilingclip starts out -1
+//
+short floorclip[SCREENWIDTH];
+short ceilingclip[SCREENWIDTH];
+
+//
+// spanstart holds the start of a plane span
+// initialized to 0 at start
+//
+int spanstart[SCREENHEIGHT];
+int spanstop[SCREENHEIGHT];
+
+//
+// texture mapping
+//
+lighttable_t** planezlight;
+fixed_t planeheight;
+
+fixed_t yslope[SCREENHEIGHT];
+fixed_t distscale[SCREENWIDTH];
+fixed_t basexscale;
+fixed_t baseyscale;
+
+fixed_t cachedheight[SCREENHEIGHT];
+fixed_t cacheddistance[SCREENHEIGHT];
+fixed_t cachedxstep[SCREENHEIGHT];
+fixed_t cachedystep[SCREENHEIGHT];
+
+
+
+//
+// R_InitPlanes
+// Only at game startup.
+//
+void R_InitPlanes (void)
+{
+ // Doh!
+}
+
+
+//
+// R_MapPlane
+//
+// Uses global vars:
+// planeheight
+// ds_source
+// basexscale
+// baseyscale
+// viewx
+// viewy
+//
+// BASIC PRIMITIVE
+//
+void
+R_MapPlane
+( int y,
+ int x1,
+ int x2 )
+{
+ angle_t angle;
+ fixed_t distance;
+ fixed_t length;
+ unsigned index;
+
+#ifdef RANGECHECK
+ if (x2 < x1
+ || x1 < 0
+ || x2 >= viewwidth
+ || y > 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;
+ ds_xfrac = viewx + FixedMul(finecosine[angle], length);
+ ds_yfrac = -viewy - FixedMul(finesine[angle], length);
+
+ if (fixedcolormap)
+ ds_colormap = fixedcolormap;
+ else
+ {
+ index = distance >> LIGHTZSHIFT;
+
+ if (index >= MAXLIGHTZ )
+ index = MAXLIGHTZ-1;
+
+ ds_colormap = planezlight[index];
+ }
+
+ ds_y = y;
+ ds_x1 = x1;
+ ds_x2 = x2;
+
+ // high or low detail
+ spanfunc ();
+}
+
+
+//
+// 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;
+ }
+
+ lastvisplane = visplanes;
+ 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);
+}
+
+
+
+
+//
+// R_FindPlane
+//
+visplane_t*
+R_FindPlane
+( fixed_t height,
+ int picnum,
+ int lightlevel )
+{
+ visplane_t* check;
+
+ if (picnum == skyflatnum)
+ {
+ height = 0; // all skys map together
+ lightlevel = 0;
+ }
+
+ for (check=visplanes; check<lastvisplane; check++)
+ {
+ if (height == check->height
+ && picnum == check->picnum
+ && lightlevel == check->lightlevel)
+ {
+ break;
+ }
+ }
+
+
+ if (check < lastvisplane)
+ return check;
+
+ if (lastvisplane - visplanes == MAXVISPLANES)
+ I_Error ("R_FindPlane: no more visplanes");
+
+ lastvisplane++;
+
+ check->height = height;
+ check->picnum = picnum;
+ check->lightlevel = lightlevel;
+ check->minx = SCREENWIDTH;
+ check->maxx = -1;
+
+ memset (check->top,0xff,sizeof(check->top));
+
+ return check;
+}
+
+
+//
+// R_CheckPlane
+//
+visplane_t*
+R_CheckPlane
+( visplane_t* pl,
+ int start,
+ int stop )
+{
+ int intrl;
+ int intrh;
+ int unionl;
+ int unionh;
+ int 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 ; x++)
+ if (pl->top[x] != 0xff)
+ break;
+
+ if (x > intrh)
+ {
+ pl->minx = unionl;
+ pl->maxx = unionh;
+
+ // use the same one
+ return pl;
+ }
+
+ // make a new visplane
+ lastvisplane->height = pl->height;
+ lastvisplane->picnum = pl->picnum;
+ lastvisplane->lightlevel = pl->lightlevel;
+
+ pl = lastvisplane++;
+ pl->minx = start;
+ pl->maxx = stop;
+
+ memset (pl->top,0xff,sizeof(pl->top));
+
+ return pl;
+}
+
+
+//
+// R_MakeSpans
+//
+void
+R_MakeSpans
+( int x,
+ int t1,
+ int b1,
+ int t2,
+ int b2 )
+{
+ while (t1 < t2 && t1<=b1)
+ {
+ R_MapPlane (t1,spanstart[t1],x-1);
+ t1++;
+ }
+ while (b1 > b2 && b1>=t1)
+ {
+ R_MapPlane (b1,spanstart[b1],x-1);
+ b1--;
+ }
+
+ while (t2 < t1 && t2<=b2)
+ {
+ spanstart[t2] = x;
+ t2++;
+ }
+ while (b2 > b1 && b2>=t2)
+ {
+ spanstart[b2] = x;
+ b2--;
+ }
+}
+
+
+
+//
+// R_DrawPlanes
+// At the end of each frame.
+//
+void R_DrawPlanes (void)
+{
+ visplane_t* pl;
+ int light;
+ int x;
+ int stop;
+ int angle;
+ int lumpnum;
+
+#ifdef RANGECHECK
+ if (ds_p - drawsegs > MAXDRAWSEGS)
+ I_Error ("R_DrawPlanes: drawsegs overflow (%i)",
+ ds_p - drawsegs);
+
+ if (lastvisplane - visplanes > MAXVISPLANES)
+ I_Error ("R_DrawPlanes: visplane overflow (%i)",
+ lastvisplane - visplanes);
+
+ if (lastopening - openings > MAXOPENINGS)
+ I_Error ("R_DrawPlanes: opening overflow (%i)",
+ lastopening - openings);
+#endif
+
+ for (pl = visplanes ; pl < lastvisplane ; pl++)
+ {
+ if (pl->minx > pl->maxx)
+ continue;
+
+
+ // sky flat
+ if (pl->picnum == skyflatnum)
+ {
+ dc_iscale = pspriteiscale>>detailshift;
+
+ // Sky is allways drawn full bright,
+ // i.e. colormaps[0] is used.
+ // Because of this hack, sky is not affected
+ // by INVUL inverse mapping.
+ dc_colormap = colormaps;
+ dc_texturemid = skytexturemid;
+ for (x=pl->minx ; x <= pl->maxx ; x++)
+ {
+ dc_yl = pl->top[x];
+ dc_yh = pl->bottom[x];
+
+ if (dc_yl <= dc_yh)
+ {
+ angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT;
+ dc_x = x;
+ dc_source = R_GetColumn(skytexture, angle);
+ colfunc ();
+ }
+ }
+ continue;
+ }
+
+ // regular flat
+ lumpnum = firstflat + flattranslation[pl->picnum];
+ ds_source = W_CacheLumpNum(lumpnum, PU_STATIC);
+
+ planeheight = abs(pl->height-viewz);
+ light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight;
+
+ if (light >= LIGHTLEVELS)
+ light = LIGHTLEVELS-1;
+
+ if (light < 0)
+ light = 0;
+
+ planezlight = zlight[light];
+
+ pl->top[pl->maxx+1] = 0xff;
+ pl->top[pl->minx-1] = 0xff;
+
+ stop = pl->maxx + 1;
+
+ 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_ReleaseLumpNum(lumpnum);
+ }
+}
diff --git a/src/strife/r_plane.h b/src/strife/r_plane.h
new file mode 100644
index 00000000..2783443d
--- /dev/null
+++ b/src/strife/r_plane.h
@@ -0,0 +1,84 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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"
+
+
+
+// Visplane related.
+extern short* lastopening;
+
+
+typedef void (*planefunction_t) (int top, int bottom);
+
+extern planefunction_t floorfunc;
+extern planefunction_t ceilingfunc_t;
+
+extern short floorclip[SCREENWIDTH];
+extern short ceilingclip[SCREENWIDTH];
+
+extern fixed_t yslope[SCREENHEIGHT];
+extern fixed_t distscale[SCREENWIDTH];
+
+void R_InitPlanes (void);
+void R_ClearPlanes (void);
+
+void
+R_MapPlane
+( int y,
+ int x1,
+ int x2 );
+
+void
+R_MakeSpans
+( int x,
+ int t1,
+ int b1,
+ int t2,
+ int b2 );
+
+void R_DrawPlanes (void);
+
+visplane_t*
+R_FindPlane
+( fixed_t height,
+ int picnum,
+ int lightlevel );
+
+visplane_t*
+R_CheckPlane
+( visplane_t* pl,
+ int start,
+ int stop );
+
+
+
+#endif
diff --git a/src/strife/r_segs.c b/src/strife/r_segs.c
new file mode 100644
index 00000000..ac7e3743
--- /dev/null
+++ b/src/strife/r_segs.c
@@ -0,0 +1,762 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+
+
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "i_system.h"
+
+#include "doomdef.h"
+#include "doomstat.h"
+
+#include "r_local.h"
+#include "r_sky.h"
+
+
+// OPTIMIZE: closed two sided lines as single sided
+
+// True if any of the segs textures might be visible.
+boolean segtextured;
+
+// False if the back side is the same plane.
+boolean markfloor;
+boolean markceiling;
+
+boolean maskedtexture;
+int toptexture;
+int bottomtexture;
+int midtexture;
+
+
+angle_t rw_normalangle;
+// angle to line origin
+int rw_angle1;
+
+//
+// regular wall
+//
+int rw_x;
+int rw_stopx;
+angle_t rw_centerangle;
+fixed_t rw_offset;
+fixed_t rw_distance;
+fixed_t rw_scale;
+fixed_t rw_scalestep;
+fixed_t rw_midtexturemid;
+fixed_t rw_toptexturemid;
+fixed_t rw_bottomtexturemid;
+
+int worldtop;
+int worldbottom;
+int worldhigh;
+int worldlow;
+
+fixed_t pixhigh;
+fixed_t pixlow;
+fixed_t pixhighstep;
+fixed_t pixlowstep;
+
+fixed_t topfrac;
+fixed_t topstep;
+
+fixed_t bottomfrac;
+fixed_t bottomstep;
+
+
+lighttable_t** walllights;
+
+short* maskedtexturecol;
+
+
+
+//
+// R_RenderMaskedSegRange
+//
+void
+R_RenderMaskedSegRange
+( drawseg_t* ds,
+ int x1,
+ int x2 )
+{
+ unsigned index;
+ column_t* col;
+ int lightnum;
+ int texnum;
+
+ // Calculate light table.
+ // Use different light tables
+ // for horizontal / vertical / diagonal. Diagonal?
+ // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
+ curline = ds->curline;
+ frontsector = curline->frontsector;
+ backsector = curline->backsector;
+ texnum = texturetranslation[curline->sidedef->midtexture];
+
+ lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
+
+ 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];
+
+ 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;
+
+ // villsa [STRIFE] render as transparent (25% or 75%?)
+ if(curline->linedef->flags & ML_TRANSPARENT1)
+ colfunc = fuzzcolfunc;
+
+ // villsa [STRIFE] render as transparent (25% or 75%?)
+ if(curline->linedef->flags & ML_TRANSPARENT2)
+ colfunc = R_DrawMVisTLColumn;
+
+ // draw the columns
+ for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
+ {
+ // calculate lighting
+ if (maskedtexturecol[dc_x] != SHRT_MAX)
+ {
+ if (!fixedcolormap)
+ {
+ index = spryscale>>LIGHTSCALESHIFT;
+
+ if (index >= MAXLIGHTSCALE )
+ index = MAXLIGHTSCALE-1;
+
+ dc_colormap = walllights[index];
+ }
+
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
+ dc_iscale = 0xffffffffu / (unsigned)spryscale;
+
+ // draw the texture
+ col = (column_t *)(
+ (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
+
+ // villsa [STRIFE] added 0 argument
+ R_DrawMaskedColumn (col, 0);
+ maskedtexturecol[dc_x] = SHRT_MAX;
+ }
+ spryscale += rw_scalestep;
+ }
+
+ colfunc = basecolfunc; // villsa [STRIFE] reset draw routines
+
+}
+
+
+
+
+//
+// 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.
+//
+#define HEIGHTBITS 12
+#define HEIGHTUNIT (1<<HEIGHTBITS)
+
+void R_RenderSegLoop (void)
+{
+ angle_t angle;
+ unsigned index;
+ int yl;
+ int yh;
+ int mid;
+ fixed_t texturecolumn;
+ int top;
+ int bottom;
+
+ for ( ; rw_x < rw_stopx ; rw_x++)
+ {
+ // mark floor / ceiling areas
+ yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS;
+
+ // no space above wall?
+ if (yl < ceilingclip[rw_x]+1)
+ yl = ceilingclip[rw_x]+1;
+
+ if (markceiling)
+ {
+ top = ceilingclip[rw_x]+1;
+ 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;
+
+ if (yh >= floorclip[rw_x])
+ yh = floorclip[rw_x]-1;
+
+ if (markfloor)
+ {
+ top = yh+1;
+ bottom = floorclip[rw_x]-1;
+ if (top <= ceilingclip[rw_x])
+ top = ceilingclip[rw_x]+1;
+ if (top <= bottom)
+ {
+ floorplane->top[rw_x] = top;
+ floorplane->bottom[rw_x] = bottom;
+ }
+ }
+
+ // texturecolumn and lighting are independent of wall tiers
+ if (segtextured)
+ {
+ // calculate texture offset
+ 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;
+ }
+ else
+ {
+ // purely to shut up the compiler
+
+ texturecolumn = 0;
+ }
+
+ // draw the wall tiers
+ if (midtexture)
+ {
+ // single sided line
+ dc_yl = yl;
+ dc_yh = yh;
+ dc_texturemid = rw_midtexturemid;
+ dc_source = R_GetColumn(midtexture,texturecolumn);
+ colfunc ();
+ ceilingclip[rw_x] = viewheight;
+ floorclip[rw_x] = -1;
+ }
+ else
+ {
+ // two sided line
+ if (toptexture)
+ {
+ // top wall
+ 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);
+ 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
+ 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);
+ colfunc ();
+ floorclip[rw_x] = mid;
+ }
+ else
+ floorclip[rw_x] = yh+1;
+ }
+ else
+ {
+ // no bottom wall
+ if (markfloor)
+ floorclip[rw_x] = yh+1;
+ }
+
+ if (maskedtexture)
+ {
+ // save texturecol
+ // for backdrawing of masked mid texture
+ maskedtexturecol[rw_x] = texturecolumn;
+ }
+ }
+
+ rw_scale += rw_scalestep;
+ topfrac += topstep;
+ bottomfrac += bottomstep;
+ }
+}
+
+
+
+
+//
+// R_StoreWallRange
+// A wall segment will be drawn
+// between start and stop pixels (inclusive).
+//
+void
+R_StoreWallRange
+( int start,
+ int stop )
+{
+ fixed_t hyp;
+ fixed_t sineval;
+ angle_t distangle, offsetangle;
+ fixed_t vtop;
+ int lightnum;
+
+ // don't overflow and crash
+ if (ds_p == &drawsegs[MAXDRAWSEGS])
+ return;
+
+#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 = abs(rw_normalangle-rw_angle1);
+
+ if (offsetangle > ANG90)
+ offsetangle = ANG90;
+
+ distangle = ANG90 - offsetangle;
+ hyp = 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;
+
+ // 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
+ {
+ // UNUSED: try to fix the stretched line bug
+#if 0
+ if (rw_distance < FRACUNIT/2)
+ {
+ fixed_t trx,try;
+ fixed_t gxt,gyt;
+
+ trx = curline->v1->x - viewx;
+ try = curline->v1->y - viewy;
+
+ gxt = FixedMul(trx,viewcos);
+ gyt = -FixedMul(try,viewsin);
+ ds_p->scale1 = FixedDiv(projection, gxt-gyt)<<detailshift;
+ }
+#endif
+ 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];
+ // a single sided line is terminal, so it must mark ends
+ markfloor = markceiling = true;
+ if (linedef->flags & ML_DONTPEGBOTTOM)
+ {
+ vtop = frontsector->floorheight +
+ textureheight[sidedef->midtexture];
+ // bottom of texture at bottom
+ rw_midtexturemid = vtop - viewz;
+ }
+ else
+ {
+ // top of texture at top
+ rw_midtexturemid = worldtop;
+ }
+ rw_midtexturemid += sidedef->rowoffset;
+
+ 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 (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;
+ // ds_p->sprbottomclip = negonearray;
+ }
+
+ 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;
+ // ds_p->sprtopclip = screenheightarray;
+ }
+
+ if (backsector->ceilingheight <= frontsector->floorheight)
+ {
+ ds_p->sprbottomclip = negonearray;
+ ds_p->bsilheight = INT_MAX;
+ ds_p->silhouette |= SIL_BOTTOM;
+ }
+
+ if (backsector->floorheight >= frontsector->ceilingheight)
+ {
+ ds_p->sprtopclip = screenheightarray;
+ ds_p->tsilheight = INT_MIN;
+ ds_p->silhouette |= SIL_TOP;
+ }
+
+ 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;
+ }
+
+
+ if (worldlow != worldbottom
+ || backsector->floorpic != frontsector->floorpic
+ || backsector->lightlevel != frontsector->lightlevel)
+ {
+ markfloor = true;
+ }
+ else
+ {
+ // same plane on both sides
+ markfloor = false;
+ }
+
+
+ if (worldhigh != worldtop
+ || backsector->ceilingpic != frontsector->ceilingpic
+ || backsector->lightlevel != frontsector->lightlevel)
+ {
+ markceiling = true;
+ }
+ else
+ {
+ // same plane on both sides
+ markceiling = false;
+ }
+
+ if (backsector->ceilingheight <= frontsector->floorheight
+ || backsector->floorheight >= frontsector->ceilingheight)
+ {
+ // closed door
+ markceiling = markfloor = true;
+ }
+
+
+ if (worldhigh < worldtop)
+ {
+ // top texture
+ toptexture = texturetranslation[sidedef->toptexture];
+ if (linedef->flags & ML_DONTPEGTOP)
+ {
+ // top of texture at top
+ rw_toptexturemid = worldtop;
+ }
+ else
+ {
+ vtop =
+ backsector->ceilingheight
+ + textureheight[sidedef->toptexture];
+
+ // bottom of texture
+ rw_toptexturemid = vtop - viewz;
+ }
+ }
+ if (worldlow > worldbottom)
+ {
+ // bottom texture
+ bottomtexture = texturetranslation[sidedef->bottomtexture];
+
+ if (linedef->flags & ML_DONTPEGBOTTOM )
+ {
+ // bottom of texture at bottom
+ // top of texture at top
+ rw_bottomtexturemid = worldtop;
+ }
+ else // top of texture at top
+ rw_bottomtexturemid = worldlow;
+ }
+ rw_toptexturemid += sidedef->rowoffset;
+ rw_bottomtexturemid += sidedef->rowoffset;
+
+ // 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)
+ {
+ lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
+
+ 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.
+
+
+ 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)
+ ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
+
+ if (markfloor)
+ floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
+
+ R_RenderSegLoop ();
+
+
+ // 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/src/strife/r_segs.h b/src/strife/r_segs.h
new file mode 100644
index 00000000..197859ed
--- /dev/null
+++ b/src/strife/r_segs.h
@@ -0,0 +1,41 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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__
+
+
+
+
+void
+R_RenderMaskedSegRange
+( drawseg_t* ds,
+ int x1,
+ int x2 );
+
+
+#endif
diff --git a/src/strife/r_sky.c b/src/strife/r_sky.c
new file mode 100644
index 00000000..97a80257
--- /dev/null
+++ b/src/strife/r_sky.c
@@ -0,0 +1,62 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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?
+//
+//
+//-----------------------------------------------------------------------------
+
+
+
+// Needed for FRACUNIT.
+#include "m_fixed.h"
+
+// Needed for Flat retrieval.
+#include "r_data.h"
+
+
+#include "r_sky.h"
+
+//
+// sky mapping
+//
+int skyflatnum;
+int skytexture;
+int skytexturemid;
+
+
+
+//
+// R_InitSkyMap
+// Called whenever the view size changes.
+//
+void R_InitSkyMap (void)
+{
+ // haleyjd 10/03/10: [STRIFE] Sky is set here, not in G_DoLoadLevel.
+ // Also skytexturemid changed from 100 to 199.
+ skyflatnum = R_FlatNumForName ( SKYFLATNAME );
+ skytexturemid = 199*FRACUNIT;
+}
+
diff --git a/src/strife/r_sky.h b/src/strife/r_sky.h
new file mode 100644
index 00000000..8cff1349
--- /dev/null
+++ b/src/strife/r_sky.h
@@ -0,0 +1,45 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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__
+
+
+
+// SKY, store the number for name.
+#define SKYFLATNAME "F_SKY001" // villsa [STRIFE]
+
+// 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/src/strife/r_state.h b/src/strife/r_state.h
new file mode 100644
index 00000000..535753c1
--- /dev/null
+++ b/src/strife/r_state.h
@@ -0,0 +1,135 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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/render internal state variables (global).
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_STATE__
+#define __R_STATE__
+
+// Need data structure definitions.
+#include "d_player.h"
+#include "r_data.h"
+
+
+
+
+
+
+//
+// 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 lighttable_t* colormaps;
+
+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
diff --git a/src/strife/r_things.c b/src/strife/r_things.c
new file mode 100644
index 00000000..f83375e8
--- /dev/null
+++ b/src/strife/r_things.c
@@ -0,0 +1,1065 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+#include <stdlib.h>
+
+
+#include "deh_main.h"
+#include "doomdef.h"
+
+#include "i_swap.h"
+#include "i_system.h"
+#include "z_zone.h"
+#include "w_wad.h"
+
+#include "r_local.h"
+
+#include "doomstat.h"
+
+// haleyjd
+#include "p_local.h"
+
+
+
+#define MINZ (FRACUNIT*4)
+#define BASEYCENTER 100
+
+//void R_DrawColumn (void);
+//void R_DrawFuzzColumn (void);
+
+
+
+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;
+
+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;
+
+spriteframe_t sprtemp[29];
+int maxframe;
+char* spritename;
+
+
+
+
+//
+// R_InstallSpriteLump
+// Local function for R_InitSprites.
+//
+void
+R_InstallSpriteLump
+( int lump,
+ unsigned frame,
+ unsigned rotation,
+ boolean flipped )
+{
+ int r;
+
+ if (frame >= 29 || 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
+ if (sprtemp[frame].rotate == false)
+ I_Error ("R_InitSprites: Sprite %s frame %c has "
+ "multip rot=0 lump", spritename, 'A'+frame);
+
+ if (sprtemp[frame].rotate == true)
+ I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
+ "and a rot=0 lump", spritename, 'A'+frame);
+
+ sprtemp[frame].rotate = false;
+ for (r=0 ; r<8 ; r++)
+ {
+ sprtemp[frame].lump[r] = lump - firstspritelump;
+ sprtemp[frame].flip[r] = (byte)flipped;
+ }
+ return;
+ }
+
+ // the lump is only used for one rotation
+ if (sprtemp[frame].rotate == false)
+ I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
+ "and a rot=0 lump", spritename, 'A'+frame);
+
+ sprtemp[frame].rotate = true;
+
+ // make 0 based
+ rotation--;
+ if (sprtemp[frame].lump[rotation] != -1)
+ I_Error ("R_InitSprites: Sprite %s : %c : %c "
+ "has two lumps mapped to it",
+ spritename, 'A'+frame, '1'+rotation);
+
+ sprtemp[frame].lump[rotation] = lump - firstspritelump;
+ sprtemp[frame].flip[rotation] = (byte)flipped;
+}
+
+
+
+
+//
+// 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 inconsistant.
+// 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.
+//
+void R_InitSpriteDefs (char** namelist)
+{
+ char** check;
+ int i;
+ int l;
+ int frame;
+ int rotation;
+ int start;
+ int end;
+ int patched;
+
+ // count the number of sprite names
+ check = namelist;
+ while (*check != NULL)
+ check++;
+
+ numsprites = check-namelist;
+
+ if (!numsprites)
+ return;
+
+ sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
+
+ start = firstspritelump-1;
+ end = lastspritelump+1;
+
+ // scan all the lump names for each of the names,
+ // noting the highest frame letter.
+ // Just compare 4 characters as ints
+ for (i=0 ; i<numsprites ; i++)
+ {
+ spritename = DEH_String(namelist[i]);
+ memset (sprtemp,-1, sizeof(sprtemp));
+
+ maxframe = -1;
+
+ // scan the lumps,
+ // filling in the frames for whatever is found
+ for (l=start+1 ; l<end ; l++)
+ {
+ if (!strncasecmp(lumpinfo[l].name, spritename, 4))
+ {
+ frame = lumpinfo[l].name[4] - 'A';
+ rotation = lumpinfo[l].name[5] - '0';
+
+ if (modifiedgame)
+ patched = W_GetNumForName (lumpinfo[l].name);
+ else
+ patched = l;
+
+ R_InstallSpriteLump (patched, frame, rotation, false);
+
+ if (lumpinfo[l].name[6])
+ {
+ frame = lumpinfo[l].name[6] - 'A';
+ rotation = lumpinfo[l].name[7] - '0';
+ R_InstallSpriteLump (l, frame, rotation, true);
+ }
+ }
+ }
+
+ // check the frames that were found for completeness
+ if (maxframe == -1)
+ {
+ sprites[i].numframes = 0;
+ continue;
+ }
+
+ maxframe++;
+
+ 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 %s frame %c", spritename, frame+'A');
+ break;
+
+ case 0:
+ // only the first rotation is needed
+ break;
+
+ case 1:
+ // must have all 8 frames
+ for (rotation=0 ; rotation<8 ; rotation++)
+ if (sprtemp[frame].lump[rotation] == -1)
+ I_Error ("R_InitSprites: Sprite %s frame %c "
+ "is missing rotations",
+ spritename, frame+'A');
+ break;
+ }
+ }
+
+ // allocate space for the frames present and copy sprtemp to it
+ sprites[i].numframes = maxframe;
+ sprites[i].spriteframes =
+ Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
+ memcpy (sprites[i].spriteframes, sprtemp, maxframe*sizeof(spriteframe_t));
+ }
+
+}
+
+
+
+
+//
+// GAME FUNCTIONS
+//
+vissprite_t vissprites[MAXVISSPRITES];
+vissprite_t* vissprite_p;
+int newvissprite;
+int sprbotscreen; // villsa [STRIFE]
+
+
+
+//
+// R_InitSprites
+// Called at program start.
+//
+void R_InitSprites (char** namelist)
+{
+ int i;
+
+ for (i=0 ; i<SCREENWIDTH ; i++)
+ {
+ negonearray[i] = -1;
+ }
+
+ R_InitSpriteDefs (namelist);
+}
+
+
+
+//
+// R_ClearSprites
+// Called at frame start.
+//
+void R_ClearSprites (void)
+{
+ vissprite_p = vissprites;
+}
+
+
+//
+// R_NewVisSprite
+//
+vissprite_t overflowsprite;
+
+vissprite_t* R_NewVisSprite (void)
+{
+ if (vissprite_p == &vissprites[MAXVISSPRITES])
+ return &overflowsprite;
+
+ vissprite_p++;
+ return vissprite_p-1;
+}
+
+
+
+//
+// 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;
+
+//
+// R_DrawMaskedColumn
+//
+// villsa [STRIFE] new baseclip argument
+//
+void R_DrawMaskedColumn (column_t *column, int baseclip)
+{
+ int topscreen;
+ int bottomscreen;
+ fixed_t basetexturemid;
+
+ basetexturemid = dc_texturemid;
+
+ for ( ; 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;
+
+ // villsa [STRIFE] checks for clipping
+ if(baseclip)
+ {
+ if(dc_yh > baseclip)
+ dc_yh = baseclip;
+ }
+
+ if (dc_yl <= dc_yh)
+ {
+ dc_source = (byte *)column + 3;
+ dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS);
+ // dc_source = (byte *)column + 3 - column->topdelta;
+
+ // Drawn by either R_DrawColumn
+ // or (SHADOW) R_DrawFuzzColumn.
+ colfunc ();
+ }
+ column = (column_t *)( (byte *)column + column->length + 4);
+ }
+
+ dc_texturemid = basetexturemid;
+}
+
+
+
+//
+// R_DrawVisSprite
+// mfloorclip and mceilingclip should also be set.
+//
+void
+R_DrawVisSprite
+( vissprite_t* vis,
+ int x1,
+ int x2 )
+{
+ column_t* column;
+ int texturecolumn;
+ fixed_t frac;
+ patch_t* patch;
+ int clip; // villsa [STRIFE]
+ int translation; // villsa [STRIFE]
+
+ patch = W_CacheLumpNum (vis->patch+firstspritelump, PU_CACHE);
+
+ dc_colormap = vis->colormap;
+
+ // villsa [STRIFE]
+ // haleyjd 09/06/10: updated MF_TRANSLATION for Strife
+ translation = vis->mobjflags & MF_TRANSLATION;
+
+ // villsa [STRIFE] unused
+ /*if (!dc_colormap)
+ {
+ // NULL colormap = shadow draw
+ colfunc = fuzzcolfunc;
+ }*/
+
+ // villsa [STRIFE] Handle the two types of translucency
+ if(vis->mobjflags & MF_SHADOW)
+ {
+ if(!translation)
+ {
+ if(vis->mobjflags & MF_MVIS)
+ colfunc = R_DrawMVisTLColumn;
+ else
+ colfunc = fuzzcolfunc;
+ }
+ else
+ {
+ colfunc = R_DrawTRTLColumn;
+ dc_translation = translationtables - 256 + (translation >> (MF_TRANSSHIFT - 8));
+ }
+ }
+ else if (translation) // villsa [STRIFE] new translation tables
+ {
+ colfunc = transcolfunc;
+ dc_translation = translationtables - 256 + (translation >> (MF_TRANSSHIFT - 8));
+ }
+
+ dc_iscale = abs(vis->xiscale)>>detailshift;
+ dc_texturemid = vis->texturemid;
+ frac = vis->startfrac;
+ spryscale = vis->scale;
+ sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale);
+
+ // villsa [STRIFE] clip sprite's feet if needed
+ if(vis->mobjflags & MF_FEETCLIPPED)
+ {
+ sprbotscreen = sprtopscreen + FixedMul(spryscale, patch->height << FRACBITS);
+ clip = (sprbotscreen - FixedMul(10*FRACUNIT, spryscale)) >> FRACBITS;
+ }
+ else
+ clip = 0;
+
+ 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 = (column_t *) ((byte *)patch +
+ LONG(patch->columnofs[texturecolumn]));
+ R_DrawMaskedColumn (column, clip); // villsa [STRIFE] clip argument
+ }
+
+ colfunc = basecolfunc;
+}
+
+
+
+//
+// R_ProjectSprite
+// Generates a vissprite for a thing
+// if it might be visible.
+//
+void R_ProjectSprite (mobj_t* thing)
+{
+ fixed_t tr_x;
+ fixed_t tr_y;
+
+ fixed_t gxt;
+ fixed_t gyt;
+
+ fixed_t tx;
+ fixed_t tz;
+
+ fixed_t xscale;
+
+ int x1;
+ int x2;
+
+ spritedef_t* sprdef;
+ spriteframe_t* sprframe;
+ int lump;
+
+ unsigned rot;
+ boolean flip;
+
+ int index;
+
+ vissprite_t* vis;
+
+ angle_t ang;
+ fixed_t iscale;
+
+ // transform the origin point
+ tr_x = thing->x - viewx;
+ tr_y = thing->y - viewy;
+
+ gxt = FixedMul(tr_x,viewcos);
+ gyt = -FixedMul(tr_y,viewsin);
+
+ 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 (abs(tx)>(tz<<2))
+ return;
+
+ // decide which patch to use for sprite relative to player
+#ifdef RANGECHECK
+ if ((unsigned int) thing->sprite >= (unsigned int) 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
+ ang = R_PointToAngle (thing->x, thing->y);
+ 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
+ tx -= 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;
+
+ // store information in a vissprite
+ vis = R_NewVisSprite ();
+ vis->mobjflags = thing->flags;
+ vis->scale = xscale<<detailshift;
+ vis->gx = thing->x;
+ vis->gy = thing->y;
+ vis->gz = thing->z;
+
+ // villsa [STRIFE]
+ if(thing->flags & MF_FEETCLIPPED)
+ vis->gz -= (10*FRACUNIT);
+
+ // villsa [STRIFE]
+ vis->gzt = vis->gz + spritetopoffset[lump];
+
+ 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
+ // villsa [STRIFE] unused
+ /*if (thing->flags & MF_SHADOW)
+ {
+ // shadow draw
+ vis->colormap = NULL;
+ }
+ else */if (fixedcolormap)
+ {
+ // fixed map
+ vis->colormap = fixedcolormap;
+ }
+ else if (thing->frame & FF_FULLBRIGHT)
+ {
+ // full bright
+ vis->colormap = colormaps;
+ }
+
+ else
+ {
+ // diminished light
+ index = xscale>>(LIGHTSCALESHIFT-detailshift);
+
+ if (index >= MAXLIGHTSCALE)
+ index = MAXLIGHTSCALE-1;
+
+ vis->colormap = spritelights[index];
+ }
+}
+
+
+
+
+//
+// R_AddSprites
+// During BSP traversal, this adds sprites by sector.
+//
+void R_AddSprites (sector_t* sec)
+{
+ 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 = (sec->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;
+ int 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 int) 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 : %i ",
+ psp->state->sprite, psp->state->frame);
+#endif
+ sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ];
+
+ lump = sprframe->lump[0];
+ // [STRIFE] haleyjd 20110629: -flip replaces this.
+ //flip = (boolean)sprframe->flip[0];
+ flip = flipparm;
+
+ // 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;
+ vis->x1 = x1 < 0 ? 0 : x1;
+ vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
+ vis->scale = pspritescale<<detailshift;
+
+ if (flip)
+ {
+ vis->xiscale = -pspriteiscale;
+ vis->startfrac = spritewidth[lump]-1;
+ }
+ else
+ {
+ vis->xiscale = pspriteiscale;
+ vis->startfrac = 0;
+ }
+
+ // villsa [STRIFE] calculate y offset with view pitch
+ vis->texturemid = ((BASEYCENTER<<FRACBITS)+FRACUNIT/2)-(psp->sy-spritetopoffset[lump])
+ + FixedMul(vis->xiscale, (centery-viewheight/2)<<FRACBITS);
+
+ 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))
+ {
+ // shadow draw
+ vis->colormap = spritelights[MAXLIGHTSCALE-1];
+ vis->mobjflags |= MF_SHADOW;
+ }
+ else if(viewplayer->powers[pw_invisibility] & 4)
+ {
+ vis->mobjflags |= (MF_SHADOW|MF_MVIS);
+ }
+
+ // When not MVIS, or if SHADOW, behave normally:
+ if(!(viewplayer->mo->flags & MF_MVIS) || (viewplayer->mo->flags & MF_SHADOW))
+ {
+ if (fixedcolormap)
+ {
+ // fixed color
+ vis->colormap = fixedcolormap;
+ }
+ else if (psp->state->frame & FF_FULLBRIGHT)
+ {
+ // full bright
+ vis->colormap = colormaps;
+ }
+ else
+ {
+ // local light
+ vis->colormap = spritelights[MAXLIGHTSCALE-1];
+ }
+ }
+ else
+ {
+ // When MVIS, use invulnerability colormap
+ vis->colormap = colormaps + INVERSECOLORMAP * 256 * sizeof(lighttable_t);
+ }
+
+ R_DrawVisSprite (vis, vis->x1, vis->x2);
+}
+
+
+
+//
+// R_DrawPlayerSprites
+//
+void R_DrawPlayerSprites (void)
+{
+ int i;
+ int 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
+//
+vissprite_t vsprsortedhead;
+
+
+void R_SortVisSprites (void)
+{
+ int i;
+ int count;
+ vissprite_t* ds;
+ vissprite_t* best;
+ vissprite_t unsorted;
+ fixed_t bestscale;
+
+ count = vissprite_p - vissprites;
+
+ unsorted.next = unsorted.prev = &unsorted;
+
+ if (!count)
+ return;
+
+ for (ds=vissprites ; ds<vissprite_p ; ds++)
+ {
+ ds->next = ds+1;
+ ds->prev = ds-1;
+ }
+
+ vissprites[0].prev = &unsorted;
+ unsorted.next = &vissprites[0];
+ (vissprite_p-1)->next = &unsorted;
+ unsorted.prev = vissprite_p-1;
+
+ // pull the vissprites out by scale
+
+ vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
+ for (i=0 ; i<count ; i++)
+ {
+ bestscale = INT_MAX;
+ best = unsorted.next;
+ for (ds=unsorted.next ; ds!= &unsorted ; ds=ds->next)
+ {
+ if (ds->scale < bestscale)
+ {
+ bestscale = ds->scale;
+ best = ds;
+ }
+ }
+ best->next->prev = best->prev;
+ best->prev->next = best->next;
+ best->next = &vsprsortedhead;
+ best->prev = vsprsortedhead.prev;
+ vsprsortedhead.prev->next = best;
+ vsprsortedhead.prev = best;
+ }
+}
+
+
+
+//
+// R_DrawSprite
+//
+void R_DrawSprite (vissprite_t* spr)
+{
+ drawseg_t* ds;
+ short clipbot[SCREENWIDTH];
+ short cliptop[SCREENWIDTH];
+ int x;
+ int r1;
+ int r2;
+ fixed_t scale;
+ fixed_t lowscale;
+ int silhouette;
+
+ 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.
+ for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
+ {
+ // determine if the drawseg obscures the sprite
+ if (ds->x1 > spr->x2
+ || ds->x2 < spr->x1
+ || (!ds->silhouette
+ && !ds->maskedtexturecol) )
+ {
+ // does not cover sprite
+ continue;
+ }
+
+ 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) ) )
+ {
+ // masked mid texture?
+ if (ds->maskedtexturecol)
+ R_RenderMaskedSegRange (ds, r1, r2);
+ // seg is behind sprite
+ continue;
+ }
+
+
+ // clip this piece of the sprite
+ silhouette = ds->silhouette;
+
+ if (spr->gz >= ds->bsilheight)
+ silhouette &= ~SIL_BOTTOM;
+
+ if (spr->gzt <= ds->tsilheight)
+ silhouette &= ~SIL_TOP;
+
+ if (silhouette == 1)
+ {
+ // bottom sil
+ for (x=r1 ; x<=r2 ; x++)
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ }
+ else if (silhouette == 2)
+ {
+ // top sil
+ for (x=r1 ; x<=r2 ; x++)
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ else if (silhouette == 3)
+ {
+ // both
+ for (x=r1 ; x<=r2 ; x++)
+ {
+ if (clipbot[x] == -2)
+ clipbot[x] = ds->sprbottomclip[x];
+ if (cliptop[x] == -2)
+ cliptop[x] = ds->sprtopclip[x];
+ }
+ }
+
+ }
+
+ // 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)
+{
+ vissprite_t* spr;
+ drawseg_t* ds;
+
+ R_SortVisSprites ();
+
+ if (vissprite_p > vissprites)
+ {
+ // draw all vissprites back to front
+ for (spr = vsprsortedhead.next ;
+ spr != &vsprsortedhead ;
+ spr=spr->next)
+ {
+
+ R_DrawSprite (spr);
+ }
+ }
+
+ // render any remaining masked mid textures
+ for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
+ 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/src/strife/r_things.h b/src/strife/r_things.h
new file mode 100644
index 00000000..0e160f01
--- /dev/null
+++ b/src/strife/r_things.h
@@ -0,0 +1,74 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 of moving objects, sprites.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_THINGS__
+#define __R_THINGS__
+
+
+
+#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;
+
+
+// villsa [STIFE] new argument
+void R_DrawMaskedColumn (column_t *column, int baseclip);
+
+
+void R_SortVisSprites (void);
+
+void R_AddSprites (sector_t* sec);
+void R_AddPSprites (void);
+void R_DrawSprites (void);
+void R_InitSprites (char** namelist);
+void R_ClearSprites (void);
+void R_DrawMasked (void);
+
+void
+R_ClipVisSprite
+( vissprite_t* vis,
+ int xl,
+ int xh );
+
+
+#endif
diff --git a/src/strife/s_sound.c b/src/strife/s_sound.c
new file mode 100644
index 00000000..ec59f3a6
--- /dev/null
+++ b/src/strife/s_sound.c
@@ -0,0 +1,828 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "i_sound.h"
+#include "i_system.h"
+
+#include "doomfeatures.h"
+#include "deh_str.h"
+
+#include "doomstat.h"
+#include "doomtype.h"
+
+#include "sounds.h"
+#include "s_sound.h"
+
+#include "m_random.h"
+#include "m_argv.h"
+
+#include "p_local.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+// when to clip out sounds
+// Does not fit the large outdoor areas.
+
+#define S_CLIPPING_DIST (1200 * FRACUNIT)
+
+// Distance tp origin when sounds should be maxed out.
+// This should relate to movement clipping resolution
+// (see BLOCKMAP handling).
+// In the source code release: (160*FRACUNIT). Changed back to the
+// Vanilla value of 200 (why was this changed?)
+
+#define S_CLOSE_DIST (200 * FRACUNIT)
+
+// The range over which sound attenuates
+
+#define S_ATTENUATOR ((S_CLIPPING_DIST - S_CLOSE_DIST) >> FRACBITS)
+
+// Stereo separation
+
+#define S_STEREO_SWING (96 * FRACUNIT)
+
+#define NORM_PITCH 128
+#define NORM_PRIORITY 64
+#define NORM_SEP 128
+
+typedef struct
+{
+ // sound information (if null, channel avail.)
+ sfxinfo_t *sfxinfo;
+
+ // origin of sound
+ mobj_t *origin;
+
+ // handle of the sound being played
+ int handle;
+
+} channel_t;
+
+// The set of channels available
+
+static channel_t *channels;
+
+// Maximum volume of a sound effect.
+// Internal default is max out of 0-15.
+
+int sfxVolume = 8;
+
+// Maximum volume of music.
+
+int musicVolume = 8;
+
+// haleyjd 08/29/10: [STRIFE] New global variable
+// Volume of voice channel.
+
+int voiceVolume = 15;
+
+// Internal volume level, ranging from 0-127
+
+static int snd_SfxVolume;
+
+// haleyjd 09/11/10: [STRIFE] Internal voice volume level
+
+static int snd_VoiceVolume;
+
+// Whether songs are mus_paused
+
+static boolean mus_paused;
+
+// Music currently being played
+
+static musicinfo_t *mus_playing = NULL;
+
+// Number of channels to use
+
+int snd_channels = 8;
+
+// haleyjd 09/11/10: [STRIFE] Handle of current voice channel.
+// This has been implemented at a higher level than it was implemented
+// in strife1.exe, as there it relied on a priority system which was
+// implicit in the SFX_PlayPatch API of DMX. Here we'll just ignore
+// the current voice channel when doing normal sound playing.
+
+static int i_voicehandle = -1;
+
+// haleyjd 09/11/10: [STRIFE] whether to play voices or not
+int disable_voices = 0;
+
+//
+// Initializes sound stuff, including volume
+// Sets channels, SFX and music volume,
+// allocates channel buffer, sets S_sfx lookup.
+//
+// haleyjd 09/11/10: [STRIFE] Added voice volume
+//
+void S_Init(int sfxVolume, int musicVolume, int voiceVolume)
+{
+ int i;
+
+ I_InitSound(true);
+ I_InitMusic();
+
+ I_PrecacheSounds(S_sfx, NUMSFX);
+
+ S_SetSfxVolume(sfxVolume);
+ S_SetMusicVolume(musicVolume);
+ S_SetVoiceVolume(voiceVolume);
+
+ // Allocating the internal channels for mixing
+ // (the maximum numer of sounds rendered
+ // simultaneously) within zone memory.
+ channels = Z_Malloc(snd_channels*sizeof(channel_t), PU_STATIC, 0);
+
+ // Free all channels for use
+ for (i=0 ; i<snd_channels ; i++)
+ {
+ channels[i].sfxinfo = 0;
+ }
+
+ // 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;
+ }
+
+ I_AtExit(S_Shutdown, true);
+}
+
+void S_Shutdown(void)
+{
+ I_ShutdownSound();
+ I_ShutdownMusic();
+}
+
+static void S_StopChannel(int cnum)
+{
+ int i;
+ channel_t *c;
+
+ c = &channels[cnum];
+
+ // haleyjd: [STRIFE] If stopping the voice channel, set i_voicehandle to -1
+ if (cnum == i_voicehandle)
+ i_voicehandle = -1;
+
+ 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<snd_channels; i++)
+ {
+ if (cnum != i && c->sfxinfo == channels[i].sfxinfo)
+ {
+ break;
+ }
+ }
+
+ // degrade usefulness of sound data
+
+ c->sfxinfo->usefulness--;
+ c->sfxinfo = NULL;
+ }
+}
+
+//
+// Per level startup code.
+// Kills playing sounds at start of level,
+// determines music if any, changes music.
+//
+// haleyjd 08/31/10: [STRIFE]
+// * Removed DOOM music handling and replaced with Strife code.
+//
+void S_Start(void)
+{
+ int cnum;
+ int mnum;
+
+ // kill all playing sounds at start of level
+ // (trust me - a good idea)
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
+ {
+ if (channels[cnum].sfxinfo)
+ {
+ S_StopChannel(cnum);
+ }
+ }
+
+ // start new music for the level
+ mus_paused = 0;
+
+ // [STRIFE] Some interesting math here ;)
+ if(gamemap <= 31)
+ mnum = 1;
+ else
+ mnum = -30;
+
+ S_ChangeMusic(gamemap + mnum, true);
+}
+
+void S_StopSound(mobj_t *origin)
+{
+ int cnum;
+
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
+ {
+ // haleyjd: do not stop voice here.
+ if(cnum == i_voicehandle)
+ continue;
+
+ if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
+ {
+ S_StopChannel(cnum);
+ break;
+ }
+ }
+}
+
+//
+// S_GetChannel :
+// If none available, return -1. Otherwise channel #.
+//
+// haleyjd 09/11/10: [STRIFE] Added an "isvoice" parameter for supporting
+// voice playing.
+//
+static int S_GetChannel(mobj_t *origin, sfxinfo_t *sfxinfo, boolean isvoice)
+{
+ // channel number to use
+ int cnum;
+
+ channel_t* c;
+
+ // Find an open channel
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
+ {
+ if (!channels[cnum].sfxinfo)
+ {
+ break;
+ }
+ else if (origin && channels[cnum].origin == origin &&
+ (isvoice || cnum != i_voicehandle)) // haleyjd
+ {
+ S_StopChannel(cnum);
+ break;
+ }
+ }
+
+ // None available
+ if (cnum == snd_channels)
+ {
+ // Look for lower priority
+ for (cnum=0 ; cnum<snd_channels ; cnum++)
+ {
+ if (channels[cnum].sfxinfo->priority >= sfxinfo->priority)
+ {
+ // haleyjd 09/11/10: [STRIFE] voice has absolute priority
+ if (isvoice || cnum != i_voicehandle)
+ break;
+ }
+ }
+
+ if (cnum == snd_channels)
+ {
+ // FUCK! No lower priority. Sorry, Charlie.
+ return -1;
+ }
+ else
+ {
+ // Otherwise, kick out lower priority.
+ S_StopChannel(cnum);
+ }
+ }
+
+ c = &channels[cnum];
+
+ // channel is decided to be cnum.
+ c->sfxinfo = sfxinfo;
+ c->origin = origin;
+
+ return cnum;
+}
+
+//
+// Changes volume and stereo-separation 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.
+//
+// [STRIFE]
+// haleyjd 20110220: changed to eliminate the gamemap == 8 hack that was
+// left over from Doom 1's original boss levels. Kind of amazing that Rogue
+// was able to catch the smallest things like that.
+//
+static int S_AdjustSoundParams(mobj_t *listener, mobj_t *source,
+ int *vol, int *sep)
+{
+ fixed_t approx_dist;
+ fixed_t adx;
+ fixed_t ady;
+ angle_t angle;
+
+ // calculate the distance to sound origin
+ // and clip it if necessary
+ adx = abs(listener->x - source->x);
+ ady = abs(listener->y - source->y);
+
+ // From _GG1_ p.428. Appox. eucledian distance fast.
+ approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1);
+
+ // [STRIFE] removed gamemap == 8 hack
+ 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 = angle - listener->angle;
+ }
+ else
+ {
+ angle = angle + (0xffffffff - listener->angle);
+ }
+
+ angle >>= ANGLETOFINESHIFT;
+
+ // stereo separation
+ *sep = 128 - (FixedMul(S_STEREO_SWING, finesine[angle]) >> FRACBITS);
+
+ // volume calculation
+ // [STRIFE] Removed gamemap == 8 hack
+ if (approx_dist < S_CLOSE_DIST)
+ {
+ *vol = snd_SfxVolume;
+ }
+ else
+ {
+ // distance effect
+ *vol = (snd_SfxVolume
+ * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
+ / S_ATTENUATOR;
+ }
+
+ return (*vol > 0);
+}
+
+void S_StartSound(void *origin_p, int sfx_id)
+{
+ sfxinfo_t *sfx;
+ mobj_t *origin;
+ int rc;
+ int sep;
+ int cnum;
+ int volume;
+
+ origin = (mobj_t *) origin_p;
+ volume = snd_SfxVolume;
+
+ // check for bogus sound #
+ if (sfx_id < 1 || sfx_id > NUMSFX)
+ {
+ // [STRIFE]: BUG - Note: vanilla had some extremely buggy and dangerous
+ // code here that tried to print the sprite name of the object playing
+ // the bad sound. Because it invokes multiple undefined behaviors and
+ // is of basically no consequence, it has deliberately not been ported.
+ I_Error("Bad sfx #: %d", sfx_id);
+ }
+
+ sfx = &S_sfx[sfx_id];
+
+ // Initialize sound parameters
+ if (sfx->link)
+ {
+ volume += sfx->volume;
+
+ if (volume < 1)
+ {
+ return;
+ }
+
+ if (volume > snd_SfxVolume)
+ {
+ volume = snd_SfxVolume;
+ }
+ }
+
+
+ // Check to see if it is audible,
+ // and if not, modify the params
+ if (origin && origin != players[consoleplayer].mo)
+ {
+ rc = S_AdjustSoundParams(players[consoleplayer].mo,
+ origin,
+ &volume,
+ &sep);
+
+ if (origin->x == players[consoleplayer].mo->x
+ && origin->y == players[consoleplayer].mo->y)
+ {
+ sep = NORM_SEP;
+ }
+
+ if (!rc)
+ {
+ return;
+ }
+ }
+ else
+ {
+ sep = NORM_SEP;
+ }
+
+ // kill old sound [STRIFE] - nope!
+ //S_StopSound(origin);
+
+ // try to find a channel
+ cnum = S_GetChannel(origin, sfx, false); // haleyjd: not a voice.
+
+ if (cnum < 0)
+ {
+ return;
+ }
+
+ // increase the usefulness
+ if (sfx->usefulness++ < 0)
+ {
+ sfx->usefulness = 1;
+ }
+
+ if (sfx->lumpnum < 0)
+ {
+ sfx->lumpnum = I_GetSfxLumpNum(sfx);
+ }
+
+ channels[cnum].handle = I_StartSound(sfx, cnum, volume, sep);
+}
+
+
+// haleyjd 09/11/10: [STRIFE]
+// None of this was necessary in the vanilla EXE but Choco's low-level code
+// won't play nice with a temporary sfxinfo because it insists that the
+// "driver_data" member remain valid from the last time the sound was used,
+// even if it has already stopped playing. Thanks to this cuteness I get
+// to maintain a dynamic cache of sfxinfo objects!
+
+typedef struct voiceinfo_s
+{
+ sfxinfo_t sfx;
+ struct voiceinfo_s *next; // next on hash chain
+} voiceinfo_t;
+
+#define NUMVOICECHAINS 257
+
+//
+// Ripped from Eternity.
+//
+static unsigned int S_voiceHash(const char *str)
+{
+ const char *c = str;
+ unsigned int h = 0;
+
+ if(!str)
+ I_Error("S_voiceHash: cannot hash NULL string!\n");
+
+ // note: this needs to be case insensitive for lump names
+ while(*c)
+ {
+ h = 5 * h + toupper(*c);
+ ++c;
+ }
+
+ return h;
+}
+
+static voiceinfo_t *voices[NUMVOICECHAINS];
+
+//
+// S_getVoice
+//
+// Gets an entry from the voice table, if it exists. If it does not, one will be
+// created.
+//
+static voiceinfo_t *S_getVoice(const char *name, int lumpnum)
+{
+ voiceinfo_t *voice;
+ unsigned int hashkey = S_voiceHash(name) % NUMVOICECHAINS;
+
+ voice = voices[hashkey];
+
+ while(voice && strcasecmp(voice->sfx.name, name))
+ voice = voice->next;
+
+ if(!voice)
+ {
+ voice = calloc(1, sizeof(voiceinfo_t));
+
+ strncpy(voice->sfx.name, name, 8);
+ voice->sfx.priority = INT_MIN; // make highest possible priority
+ voice->sfx.pitch = -1;
+ voice->sfx.volume = -1;
+ voice->sfx.numchannels = -1;
+ voice->sfx.usefulness = -1;
+ voice->sfx.lumpnum = lumpnum;
+
+ // throw it onto the table.
+ voice->next = voices[hashkey];
+ voices[hashkey] = voice;
+ }
+
+ return voice;
+}
+
+//
+// I_StartVoice
+//
+// haleyjd 09/11/10: [STRIFE] New function
+// Note this was in i_sound.c in Strife itself, but relied on DMX-specific
+// features to ensure voice channels had absolute priority. Here we must
+// populate a fake sfxinfo_t and send the sound through some of the normal
+// routines. But in the end, it still works the same.
+//
+void I_StartVoice(const char *lumpname)
+{
+ int lumpnum;
+ voiceinfo_t *voice; // choco-specific
+ char lumpnamedup[9];
+
+ // no voices in deathmatch mode.
+ if(netgame)
+ return;
+
+ // STRIFE-TODO: checks if snd_SfxDevice == 83
+ // This is probably turning off voice if using PC speaker...
+
+ // user has disabled voices?
+ if(disable_voices)
+ return;
+
+ // have a voice playing already? stop it.
+ if(i_voicehandle >= 0)
+ S_StopChannel(i_voicehandle);
+
+ // Vanilla STRIFE appears to have stopped any current voice without
+ // starting a new one if NULL was passed in here, though I cannot
+ // find an explicit check for NULL in the assembly. Either way, it
+ // didn't crash, so do a check now:
+ if(lumpname == NULL)
+ return;
+
+ // Because of constness problems...
+ strncpy(lumpnamedup, lumpname, 9);
+ lumpnamedup[8] = '\0';
+
+ if((lumpnum = W_CheckNumForName(lumpnamedup)) != -1)
+ {
+ // haleyjd: Choco-specific: get a voice structure
+ voice = S_getVoice(lumpnamedup, lumpnum);
+
+ // get a channel for the voice
+ i_voicehandle = S_GetChannel(NULL, &voice->sfx, true);
+
+ channels[i_voicehandle].handle
+ = I_StartSound(&voice->sfx, i_voicehandle, snd_VoiceVolume, NORM_SEP);
+ }
+}
+
+//
+// Stop and resume music, during game PAUSE.
+//
+
+void S_PauseSound(void)
+{
+ if (mus_playing && !mus_paused)
+ {
+ I_PauseSong();
+ mus_paused = true;
+ }
+}
+
+void S_ResumeSound(void)
+{
+ if (mus_playing && mus_paused)
+ {
+ I_ResumeSong();
+ mus_paused = false;
+ }
+}
+
+//
+// Updates music & sounds
+//
+
+void S_UpdateSounds(mobj_t *listener)
+{
+ int audible;
+ int cnum;
+ int volume;
+ int sep;
+ sfxinfo_t* sfx;
+ channel_t* c;
+
+ I_UpdateSound();
+
+ for (cnum=0; cnum<snd_channels; cnum++)
+ {
+ c = &channels[cnum];
+ sfx = c->sfxinfo;
+
+ if (c->sfxinfo)
+ {
+ if (I_SoundIsPlaying(c->handle))
+ {
+ // initialize parameters
+ volume = snd_SfxVolume;
+ sep = NORM_SEP;
+
+ if (sfx->link)
+ {
+ 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 != c->origin)
+ {
+ audible = S_AdjustSoundParams(listener,
+ c->origin,
+ &volume,
+ &sep);
+
+ if (!audible)
+ {
+ S_StopChannel(cnum);
+ }
+ else
+ {
+ I_UpdateSoundParams(c->handle, volume, sep);
+ }
+ }
+ }
+ else
+ {
+ // if channel is allocated but sound has stopped,
+ // free it
+ S_StopChannel(cnum);
+ }
+ }
+ }
+}
+
+void S_SetMusicVolume(int volume)
+{
+ if (volume < 0 || volume > 127)
+ {
+ I_Error("Attempt to set music volume at %d",
+ volume);
+ }
+
+ I_SetMusicVolume(volume);
+}
+
+void S_SetSfxVolume(int volume)
+{
+ if (volume < 0 || volume > 127)
+ {
+ I_Error("Attempt to set sfx volume at %d", volume);
+ }
+
+ snd_SfxVolume = volume;
+}
+
+//
+// S_SetVoiceVolume
+//
+// haleyjd 09/11/10: [STRIFE]
+// Set the internal voice volume level.
+//
+void S_SetVoiceVolume(int volume)
+{
+ if (volume < 0 || volume > 127)
+ {
+ I_Error("Attempt to set voice volume at %d", volume);
+ }
+
+ snd_VoiceVolume = volume;
+}
+
+//
+// Starts some music with the music id found in sounds.h.
+//
+
+void S_StartMusic(int m_id)
+{
+ S_ChangeMusic(m_id, false);
+}
+
+void S_ChangeMusic(int musicnum, int looping)
+{
+ musicinfo_t *music = NULL;
+ char namebuf[9];
+ void *handle;
+
+ if (musicnum <= mus_None || musicnum >= NUMMUSIC)
+ {
+ I_Error("Bad music number %d", musicnum);
+ }
+ else
+ {
+ music = &S_music[musicnum];
+ }
+
+ if (mus_playing == music)
+ {
+ return;
+ }
+
+ // shutdown old music
+ S_StopMusic();
+
+ // get lumpnum if neccessary
+ if (!music->lumpnum)
+ {
+ sprintf(namebuf, "d_%s", DEH_String(music->name));
+ music->lumpnum = W_GetNumForName(namebuf);
+ }
+
+ music->data = W_CacheLumpNum(music->lumpnum, PU_STATIC);
+
+ handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum));
+ music->handle = handle;
+ I_PlaySong(handle, looping);
+
+ mus_playing = music;
+}
+
+boolean S_MusicPlaying(void)
+{
+ return I_MusicIsPlaying();
+}
+
+void S_StopMusic(void)
+{
+ if (mus_playing)
+ {
+ if (mus_paused)
+ {
+ I_ResumeSong();
+ }
+
+ I_StopSong();
+ I_UnRegisterSong(mus_playing->handle);
+ W_ReleaseLumpNum(mus_playing->lumpnum);
+ mus_playing->data = NULL;
+ mus_playing = NULL;
+ }
+}
+
diff --git a/src/strife/s_sound.h b/src/strife/s_sound.h
new file mode 100644
index 00000000..5e763014
--- /dev/null
+++ b/src/strife/s_sound.h
@@ -0,0 +1,103 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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__
+
+#include "p_mobj.h"
+#include "sounds.h"
+
+//
+// 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, int voiceVolume);
+
+
+// Shut down sound
+
+void S_Shutdown(void);
+
+
+
+//
+// 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);
+
+// haleyjd 09/11/10: [STRIFE] Start a voice.
+void I_StartVoice(const char *lumpname);
+
+// Stop sound for thing at <origin>
+void S_StopSound(mobj_t *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);
+
+// query if music is playing
+boolean S_MusicPlaying(void);
+
+// 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(mobj_t *listener);
+
+void S_SetMusicVolume(int volume);
+void S_SetSfxVolume(int volume);
+void S_SetVoiceVolume(int volume); // haleyjd 09/11/10: [STRIFE]
+
+extern int snd_channels;
+
+extern int disable_voices;
+
+#endif
+
diff --git a/src/strife/sounds.c b/src/strife/sounds.c
new file mode 100644
index 00000000..c87dd6d4
--- /dev/null
+++ b/src/strife/sounds.c
@@ -0,0 +1,235 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdlib.h>
+
+
+#include "doomtype.h"
+#include "sounds.h"
+
+//
+// Information about all the music
+//
+
+#define MUSIC(name) \
+ { name, 0, NULL, NULL }
+
+// villsa [STRIFE]
+musicinfo_t S_music[] =
+{
+ MUSIC(NULL),
+ MUSIC("logo"),
+ MUSIC("action"),
+ MUSIC("tavern"),
+ MUSIC("danger"),
+ MUSIC("fast"),
+ MUSIC("intro"),
+ MUSIC("darker"),
+ MUSIC("strike"),
+ MUSIC("slide"),
+ MUSIC("tribal"),
+ MUSIC("march"),
+ MUSIC("danger"),
+ MUSIC("mood"),
+ MUSIC("castle"),
+ MUSIC("darker"),
+ MUSIC("action"),
+ MUSIC("fight"),
+ MUSIC("spense"),
+ MUSIC("slide"),
+ MUSIC("strike"),
+ MUSIC("dark"),
+ MUSIC("tech"),
+ MUSIC("slide"),
+ MUSIC("drone"),
+ MUSIC("panthr"),
+ MUSIC("sad"),
+ MUSIC("instry"),
+ MUSIC("tech"),
+ MUSIC("action"),
+ MUSIC("instry"),
+ MUSIC("drone"),
+ MUSIC("fight"),
+ MUSIC("happy"),
+ MUSIC("end")
+
+
+};
+
+
+//
+// Information about all the sfx
+//
+
+#define SOUND(name, priority) \
+ { NULL, name, priority, NULL, -1, -1, 0, 0, -1, NULL }
+#define SOUND_LINK(name, priority, link_id, pitch, volume) \
+ { NULL, name, priority, &S_sfx[link_id], pitch, volume, 0, 0, -1, NULL }
+
+// villsa [STRIFE]
+sfxinfo_t S_sfx[] =
+{
+ // S_sfx[0] needs to be a dummy for odd reasons.
+ SOUND("none", 0),
+ SOUND("swish", 64),
+ SOUND("meatht", 64),
+ SOUND("mtalht", 64),
+ SOUND("wpnup", 78),
+ SOUND("rifle", 64),
+ SOUND("mislht", 64),
+ SOUND("barexp", 32),
+ SOUND("flburn", 64),
+ SOUND("flidl", 118),
+ SOUND("agrsee", 98),
+ SOUND("plpain", 96),
+ SOUND("pcrush", 96),
+ SOUND("pespna", 98),
+ SOUND("pespnb", 98),
+ SOUND("pespnc", 98),
+ SOUND("pespnd", 98),
+ SOUND("agrdpn", 98),
+ SOUND("pldeth", 32),
+ SOUND("plxdth", 32),
+ SOUND("slop", 78),
+ SOUND("rebdth", 98),
+ SOUND("agrdth", 98),
+ SOUND("lgfire", 211),
+ SOUND("smfire", 211),
+ SOUND("alarm", 210),
+ SOUND("drlmto", 98),
+ SOUND("drlmtc", 98),
+ SOUND("drsmto", 98),
+ SOUND("drsmtc", 98),
+ SOUND("drlwud", 98),
+ SOUND("drswud", 98),
+ SOUND("drston", 98),
+ SOUND("bdopn", 98),
+ SOUND("bdcls", 98),
+ SOUND("swtchn", 78),
+ SOUND("swbolt", 98),
+ SOUND("swscan", 98),
+ SOUND("yeah", 10),
+ SOUND("mask", 210),
+ SOUND("pstart", 100),
+ SOUND("pstop", 100),
+ SOUND("itemup", 78),
+ SOUND("bglass", 200),
+ SOUND("wriver", 201),
+ SOUND("wfall", 201),
+ SOUND("wdrip", 201),
+ SOUND("wsplsh", 95),
+ SOUND("rebact", 200),
+ SOUND("agrac1", 98),
+ SOUND("agrac2", 98),
+ SOUND("agrac3", 98),
+ SOUND("agrac4", 98),
+ SOUND("ambppl", 218),
+ SOUND("ambbar", 218),
+ SOUND("telept", 32),
+ SOUND("ratact", 99),
+ SOUND("itmbk", 100),
+ SOUND("xbow", 99),
+ SOUND("burnme", 95),
+ SOUND("oof", 96),
+ SOUND("wbrldt", 98),
+ SOUND("psdtha", 109),
+ SOUND("psdthb", 109),
+ SOUND("psdthc", 109),
+ SOUND("rb2pn", 96),
+ SOUND("rb2dth", 32),
+ SOUND("rb2see", 98),
+ SOUND("rb2act", 98),
+ SOUND("firxpl", 70),
+ SOUND("stnmov", 100),
+ SOUND("noway", 78),
+ SOUND("rlaunc", 64),
+ SOUND("rflite", 65),
+ SOUND("radio", 60),
+ SOUND("pulchn", 98),
+ SOUND("swknob", 98),
+ SOUND("keycrd", 98),
+ SOUND("swston", 98),
+ SOUND("sntsee", 98),
+ SOUND("sntdth", 98),
+ SOUND("sntact", 98),
+ SOUND("pgrdat", 64),
+ SOUND("pgrsee", 90),
+ SOUND("pgrdpn", 96),
+ SOUND("pgrdth", 32),
+ SOUND("pgract", 120),
+ SOUND("proton", 64),
+ SOUND("protfl", 64),
+ SOUND("plasma", 64),
+ SOUND("dsrptr", 30),
+ SOUND("reavat", 64),
+ SOUND("revbld", 64),
+ SOUND("revsee", 90),
+ SOUND("reavpn", 96),
+ SOUND("revdth", 32),
+ SOUND("revact", 120),
+ SOUND("spisit", 90),
+ SOUND("spdwlk", 65),
+ SOUND("spidth", 32),
+ SOUND("spdatk", 32),
+ SOUND("chant", 218),
+ SOUND("static", 32),
+ SOUND("chain", 70),
+ SOUND("tend", 100),
+ SOUND("phoot", 32),
+ SOUND("explod", 32),
+ SOUND("sigil", 32),
+ SOUND("sglhit", 32),
+ SOUND("siglup", 32),
+ SOUND("prgpn", 96),
+ SOUND("progac", 120),
+ SOUND("lorpn", 96),
+ SOUND("lorsee", 90),
+ SOUND("difool", 32),
+ SOUND("inqdth", 32),
+ SOUND("inqact", 98),
+ SOUND("inqsee", 90),
+ SOUND("inqjmp", 65),
+ SOUND("amaln1", 99),
+ SOUND("amaln2", 99),
+ SOUND("amaln3", 99),
+ SOUND("amaln4", 99),
+ SOUND("amaln5", 99),
+ SOUND("amaln6", 99),
+ SOUND("mnalse", 64),
+ SOUND("alnsee", 64),
+ SOUND("alnpn", 96),
+ SOUND("alnact", 120),
+ SOUND("alndth", 32),
+ SOUND("mnaldt", 32),
+ SOUND("reactr", 31),
+ SOUND("airlck", 98),
+ SOUND("drchno", 98),
+ SOUND("drchnc", 98),
+ SOUND("valve", 98)
+};
+
diff --git a/src/strife/sounds.h b/src/strife/sounds.h
new file mode 100644
index 00000000..4236a5da
--- /dev/null
+++ b/src/strife/sounds.h
@@ -0,0 +1,230 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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__
+
+#include "i_sound.h"
+
+// 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.
+//
+
+// villsa [STRIFE]
+typedef enum
+{
+ mus_None,
+ mus_logo,
+ mus_action,
+ mus_tavern,
+ mus_danger,
+ mus_fast,
+ mus_intro,
+ mus_darker,
+ mus_strike,
+ mus_slide,
+ mus_tribal,
+ mus_march,
+ mus_danger2,
+ mus_mood,
+ mus_castle,
+ mus_darker2,
+ mus_action2,
+ mus_fight,
+ mus_spense,
+ mus_slide2,
+ mus_strike2,
+ mus_dark,
+ mus_tech,
+ mus_slide3,
+ mus_drone,
+ mus_panthr,
+ mus_sad,
+ mus_instry,
+ mus_tech2,
+ mus_action3,
+ mus_instry2,
+ mus_drone2,
+ mus_fight2,
+ mus_happy,
+ mus_end,
+ NUMMUSIC
+} musicenum_t;
+
+
+//
+// Identifiers for all sfx in game.
+//
+
+typedef enum
+{
+ sfx_None,
+ sfx_swish,
+ sfx_meatht,
+ sfx_mtalht,
+ sfx_wpnup,
+ sfx_rifle,
+ sfx_mislht,
+ sfx_barexp,
+ sfx_flburn,
+ sfx_flidl,
+ sfx_agrsee,
+ sfx_plpain,
+ sfx_pcrush,
+ sfx_pespna,
+ sfx_pespnb,
+ sfx_pespnc,
+ sfx_pespnd,
+ sfx_agrdpn,
+ sfx_pldeth,
+ sfx_plxdth,
+ sfx_slop,
+ sfx_rebdth,
+ sfx_agrdth,
+ sfx_lgfire,
+ sfx_smfire,
+ sfx_alarm,
+ sfx_drlmto,
+ sfx_drlmtc,
+ sfx_drsmto,
+ sfx_drsmtc,
+ sfx_drlwud,
+ sfx_drswud,
+ sfx_drston,
+ sfx_bdopn,
+ sfx_bdcls,
+ sfx_swtchn,
+ sfx_swbolt,
+ sfx_swscan,
+ sfx_yeah,
+ sfx_mask,
+ sfx_pstart,
+ sfx_pstop,
+ sfx_itemup,
+ sfx_bglass,
+ sfx_wriver,
+ sfx_wfall,
+ sfx_wdrip,
+ sfx_wsplsh,
+ sfx_rebact,
+ sfx_agrac1,
+ sfx_agrac2,
+ sfx_agrac3,
+ sfx_agrac4,
+ sfx_ambppl,
+ sfx_ambbar,
+ sfx_telept,
+ sfx_ratact,
+ sfx_itmbk,
+ sfx_xbow,
+ sfx_burnme,
+ sfx_oof,
+ sfx_wbrldt,
+ sfx_psdtha,
+ sfx_psdthb,
+ sfx_psdthc,
+ sfx_rb2pn,
+ sfx_rb2dth,
+ sfx_rb2see,
+ sfx_rb2act,
+ sfx_firxpl,
+ sfx_stnmov,
+ sfx_noway,
+ sfx_rlaunc,
+ sfx_rflite,
+ sfx_radio,
+ sfx_pulchn,
+ sfx_swknob,
+ sfx_keycrd,
+ sfx_swston,
+ sfx_sntsee,
+ sfx_sntdth,
+ sfx_sntact,
+ sfx_pgrdat,
+ sfx_pgrsee,
+ sfx_pgrdpn,
+ sfx_pgrdth,
+ sfx_pgract,
+ sfx_proton,
+ sfx_protfl,
+ sfx_plasma,
+ sfx_dsrptr,
+ sfx_reavat,
+ sfx_revbld,
+ sfx_revsee,
+ sfx_reavpn,
+ sfx_revdth,
+ sfx_revact,
+ sfx_spisit,
+ sfx_spdwlk,
+ sfx_spidth,
+ sfx_spdatk,
+ sfx_chant,
+ sfx_static,
+ sfx_chain,
+ sfx_tend,
+ sfx_phoot,
+ sfx_explod,
+ sfx_sigil,
+ sfx_sglhit,
+ sfx_siglup,
+ sfx_prgpn,
+ sfx_progac,
+ sfx_lorpn,
+ sfx_lorsee,
+ sfx_difool,
+ sfx_inqdth,
+ sfx_inqact,
+ sfx_inqsee,
+ sfx_inqjmp,
+ sfx_amaln1,
+ sfx_amaln2,
+ sfx_amaln3,
+ sfx_amaln4,
+ sfx_amaln5,
+ sfx_amaln6,
+ sfx_mnalse,
+ sfx_alnsee,
+ sfx_alnpn,
+ sfx_alnact,
+ sfx_alndth,
+ sfx_mnaldt,
+ sfx_reactr,
+ sfx_airlck,
+ sfx_drchno,
+ sfx_drchnc,
+ sfx_valve,
+ NUMSFX
+} sfxenum_t;
+
+#endif
diff --git a/src/strife/st_lib.c b/src/strife/st_lib.c
new file mode 100644
index 00000000..a0fed423
--- /dev/null
+++ b/src/strife/st_lib.c
@@ -0,0 +1,340 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+#include <ctype.h>
+
+#include "deh_main.h"
+#include "doomdef.h"
+
+#include "z_zone.h"
+#include "v_video.h"
+
+#include "i_swap.h"
+#include "i_system.h"
+
+#include "w_wad.h"
+
+#include "st_stuff.h"
+#include "st_lib.h"
+#include "r_local.h"
+
+
+// in AM_map.c
+extern boolean automapactive;
+
+
+
+
+//
+// Hack display negative frags.
+// Loads and store the stminus lump.
+//
+patch_t* sttminus;
+
+void STlib_init(void)
+{
+ // haleyjd 08/28/10: [STRIFE] STTMINUS -> STCFN045
+ sttminus = (patch_t *) W_CacheLumpName(DEH_String("STCFN045"), PU_STATIC);
+}
+
+
+//
+// STlib_initNum
+//
+// haleyjd 09/01/10: [STRIFE]
+// * Rogue removed the "on" member of st_number_t.
+void
+STlib_initNum
+( st_number_t* n,
+ int x,
+ int y,
+ patch_t** pl,
+ int* num,
+ int width )
+{
+ n->x = x;
+ n->y = y;
+ n->width = width;
+ n->num = num;
+ n->p = pl;
+}
+
+
+//
+// STlib_drawNum
+//
+// A fairly efficient way to draw a number
+// based on differences from the old number.
+// Note: worth the trouble?
+//
+// haleyjd 09/01/10: [STRIFE]
+// * Rogue removed the "refresh" parameter and caching code
+//
+void
+STlib_drawNum
+( st_number_t* n)
+{
+ int numdigits = n->width;
+ int num = *n->num;
+
+ int w = SHORT(n->p[0]->width) + 1; // [STRIFE] +1
+ int x = n->x;
+
+ int neg;
+
+ neg = num < 0;
+
+ if (neg)
+ {
+ if (numdigits == 2 && num < -9)
+ num = -9;
+ else if (numdigits == 3 && num < -99)
+ num = -99;
+
+ num = -num;
+ }
+
+ /* haleyjd 09/01/10: [STRIFE] Widget caching system removed by Rogue
+ // clear the area
+ x = n->x - numdigits*w;
+
+ if (n->y - ST_Y < 0)
+ I_Error("drawNum: n->y - ST_Y < 0");
+
+ V_CopyRect(x, n->y - ST_Y, st_backing_screen, w*numdigits, h, x, n->y);
+ */
+
+ // if non-number, do not draw it
+ if (num == 1994)
+ return;
+
+ x = n->x;
+
+ // in the special case of 0, you draw 0
+ if (!num)
+ V_DrawPatch(x - w, n->y, n->p[ 0 ]);
+
+ // draw the new number
+ while (num && numdigits--)
+ {
+ x -= w;
+ V_DrawPatch(x, n->y, n->p[ num % 10 ]);
+ num /= 10;
+ }
+
+ // draw a minus sign if necessary
+ if (neg)
+ V_DrawPatch(x - 8, n->y, sttminus);
+}
+
+
+//
+// STlib_drawNumPositive
+//
+// haleyjd 09/01/10: [STRIFE] New function.
+// * Mostly the same as STlib_drawNum, except doesn't draw negatives.
+//
+void
+STlib_drawNumPositive
+( st_number_t* n)
+{
+ int numdigits = n->width;
+ int num = *n->num;
+
+ int w = SHORT(n->p[0]->width) + 1; // [STRIFE] +1
+ int x = n->x;
+
+ // Don't draw negative values.
+ if (num < 0)
+ num = 0;
+
+ // if non-number, do not draw it
+ if (num == 1994)
+ return;
+
+ x = n->x;
+
+ // in the special case of 0, you draw 0
+ if (!num)
+ V_DrawPatch(x - w, n->y, n->p[ 0 ]);
+
+ // draw the new number
+ while (num && numdigits--)
+ {
+ x -= w;
+ V_DrawPatch(x, n->y, n->p[ num % 10 ]);
+ num /= 10;
+ }
+}
+
+
+// haleyjd 09/01/10: [STRIFE] All other functions were removed.
+/*
+void
+STlib_updateNum
+( st_number_t* n,
+ boolean refresh )
+{
+ if (*n->on) STlib_drawNum(n, refresh);
+}
+
+
+//
+void
+STlib_initPercent
+( st_percent_t* p,
+ int x,
+ int y,
+ patch_t** pl,
+ int* num,
+ boolean* on,
+ patch_t* percent )
+{
+ STlib_initNum(&p->n, x, y, pl, num, on, 3);
+ p->p = percent;
+}
+
+
+
+
+void
+STlib_updatePercent
+( st_percent_t* per,
+ int refresh )
+{
+ if (refresh && *per->n.on)
+ V_DrawPatch(per->n.x, per->n.y, per->p);
+
+ STlib_updateNum(&per->n, refresh);
+}
+
+
+
+void
+STlib_initMultIcon
+( st_multicon_t* i,
+ int x,
+ int y,
+ patch_t** il,
+ int* inum,
+ boolean* on )
+{
+ i->x = x;
+ i->y = y;
+ i->oldinum = -1;
+ i->inum = inum;
+ i->on = on;
+ i->p = il;
+}
+
+
+
+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)
+ && (*mi->inum!=-1))
+ {
+ 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);
+
+ if (y - ST_Y < 0)
+ I_Error("updateMultIcon: y - ST_Y < 0");
+
+ V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y);
+ }
+ V_DrawPatch(mi->x, mi->y, mi->p[*mi->inum]);
+ mi->oldinum = *mi->inum;
+ }
+}
+
+
+
+void
+STlib_initBinIcon
+( st_binicon_t* b,
+ int x,
+ int y,
+ patch_t* i,
+ boolean* val,
+ boolean* on )
+{
+ b->x = x;
+ b->y = y;
+ b->oldval = false;
+ b->val = val;
+ b->on = on;
+ b->p = i;
+}
+
+
+
+void
+STlib_updateBinIcon
+( st_binicon_t* bi,
+ boolean refresh )
+{
+ int x;
+ int y;
+ int w;
+ int h;
+
+ if (*bi->on
+ && (bi->oldval != *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);
+
+ if (y - ST_Y < 0)
+ I_Error("updateBinIcon: y - ST_Y < 0");
+
+ if (*bi->val)
+ V_DrawPatch(bi->x, bi->y, bi->p);
+ else
+ V_CopyRect(x, y-ST_Y, st_backing_screen, w, h, x, y);
+
+ bi->oldval = *bi->val;
+ }
+
+}
+*/
+
diff --git a/src/strife/st_lib.h b/src/strife/st_lib.h
new file mode 100644
index 00000000..2576233d
--- /dev/null
+++ b/src/strife/st_lib.h
@@ -0,0 +1,229 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __STLIB__
+#define __STLIB__
+
+
+// We are referring to patches.
+#include "r_defs.h"
+
+//
+// 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;
+
+ // haleyjd 09/01/10: [STRIFE] Removed "oldnum" member
+ //int oldnum;
+
+ // pointer to current value
+ int* num;
+
+ // haleyjd 09/01/10: [STRIFE] Removed "on" member
+ // boolean* on;
+
+ // list of patches for 0-9
+ patch_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
+ patch_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
+ patch_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
+ boolean oldval;
+
+ // pointer to current icon status
+ boolean* val;
+
+ // pointer to boolean
+ // stating whether to update icon
+ boolean* on;
+
+
+ patch_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
+
+// haleyjd 09/01/10: [STRIFE] Removed "on" parameter.
+void
+STlib_initNum
+( st_number_t* n,
+ int x,
+ int y,
+ patch_t** pl,
+ int* num,
+ int width );
+
+// haleyjd 09/01/10: [STRIFE] Made globally visible.
+void
+STlib_drawNum
+( st_number_t* n);
+
+// haleyjd 09/01/10: [STRIFE] New function
+void
+STlib_drawNumPositive
+( st_number_t* n);
+
+/* haleyjd 09/01/10: [STRIFE] All the below were removed
+void
+STlib_updateNum
+( st_number_t* n,
+ boolean refresh );
+
+
+// Percent widget routines
+void
+STlib_initPercent
+( st_percent_t* p,
+ int x,
+ int y,
+ patch_t** pl,
+ int* num,
+ boolean* on,
+ patch_t* percent );
+
+
+void
+STlib_updatePercent
+( st_percent_t* per,
+ int refresh );
+
+
+// Multiple Icon widget routines
+void
+STlib_initMultIcon
+( st_multicon_t* mi,
+ int x,
+ int y,
+ patch_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,
+ patch_t* i,
+ boolean* val,
+ boolean* on );
+
+void
+STlib_updateBinIcon
+( st_binicon_t* bi,
+ boolean refresh );
+*/
+
+#endif
diff --git a/src/strife/st_stuff.c b/src/strife/st_stuff.c
new file mode 100644
index 00000000..3761f141
--- /dev/null
+++ b/src/strife/st_stuff.c
@@ -0,0 +1,1555 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+
+#include "i_system.h"
+#include "i_video.h"
+#include "z_zone.h"
+#include "m_random.h"
+#include "w_wad.h"
+
+#include "deh_main.h"
+#include "deh_misc.h"
+#include "doomdef.h"
+#include "doomkeys.h"
+
+#include "g_game.h"
+
+#include "st_stuff.h"
+#include "st_lib.h"
+#include "r_local.h"
+
+#include "p_local.h"
+#include "p_inter.h"
+#include "p_dialog.h" // villsa [STRIFE]
+
+#include "am_map.h"
+#include "m_cheat.h"
+#include "m_menu.h" // villsa [STRIFE]
+
+#include "s_sound.h"
+
+// Needs access to LFB.
+#include "v_video.h"
+#include "i_swap.h"
+
+// State.
+#include "doomstat.h"
+#include "d_main.h" // [STRIFE]
+
+// Data.
+#include "dstrings.h"
+#include "sounds.h"
+#include "m_controls.h"
+#include "hu_lib.h" // [STRIFE]
+#include "hu_stuff.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
+
+// 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?
+
+// AMMO number pos.
+// haleyjd 09/01/10: [STRIFE] Adjusted.
+#define ST_AMMOWIDTH 3
+#define ST_AMMOX 311
+#define ST_AMMOY 162
+
+// HEALTH number pos.
+// haleyjd 09/01/10: [STRIFE] Adjusted.
+#define ST_HEALTHWIDTH 3
+#define ST_HEALTHX 79
+#define ST_HEALTHY 162
+
+// [STRIFE]
+// Removed:
+// * Weapon pos.
+// * Frags pos.
+// * ARMOR number pos.
+// * Key icon positions.
+
+// Ammunition counter.
+// haleyjd 20110213 [STRIFE]: ammo counters for the popup widget
+#define ST_POPUPAMMOX 206
+static const int st_yforammo[NUMAMMO] = { 75, 99, 91, 139, 131, 115, 123 };
+static const int st_wforammo[NUMAMMO] = { 3, 3, 2, 3, 3, 2, 3 };
+
+// Indicate maximum ammunition.
+// Only needed because backpack exists.
+// haleyjd 20110213 [STRIFE]: maxammo counters for the popup widget
+#define ST_POPUPMAXAMMOX 239
+
+// [STRIFE]
+// Removed:
+// * Doom weapon stuff
+// * DETH title (???)
+
+// Dimensions given in characters.
+#define ST_MSGWIDTH 52
+
+// haleyjd 08/31/10: [STRIFE]
+// * Removed faces.
+// haleyjd 09/01/10:
+// * Removed DOOM pre-beta cruft.
+// * Removed deathmatch frags/arms-related stuff.
+// * Removed arms panel stuff.
+// * Removed unused widgets.
+// * Removed more faces, keyboxes, st_randomnumber
+
+// graphics are drawn to a backing screen and blitted to the real screen
+//byte *st_backing_screen; - [STRIFE]: Unused.
+
+// main player in game
+static player_t* plyr;
+
+// ST_Start() has just been called
+static boolean st_firsttime;
+
+// lump number for PLAYPAL
+static int lu_palette;
+
+// whether in automap or first-person
+static st_stateenum_t st_gamestate;
+
+// whether left-side main status bar is active
+static boolean st_statusbaron;
+
+// villsa [STRIFE]
+static boolean st_dosizedisplay = false;
+
+// haleyjd 09/01/10: [STRIFE]
+// Whether or not a popup is currently displayed
+static boolean st_displaypopup = false;
+
+// villsa [STRIFE]
+static int st_popupdisplaytics = 0;
+
+// villsa [STRIFE]
+// Whether or not show popup objective screen
+static boolean st_showobjective = false;
+
+// villsa [STRIFE]
+static boolean st_showinvpop = false;
+
+// villsa [STRIFE]
+static boolean st_showkeys = false;
+
+// villsa [STRIFE] TODO - identify variables
+static int st_keypage = -1;
+static int dword_88490 = 0;
+
+// haleyjd 09/19/10: [STRIFE] Cached player data
+static int st_lastcursorpos;
+static int st_lastammo;
+static int st_lastarmortype;
+static int st_lasthealth;
+
+// haleyjd 09/01/10: [STRIFE] sbar -> invback
+// main inventory background and other bits
+static patch_t* invback; // main bar
+static patch_t* stback; // multiplayer background
+static patch_t* invtop; // top bit
+static patch_t* invpop; // popup frame with text
+static patch_t* invpop2; // plain popup frame
+static patch_t* invpbak; // popup background w/details
+static patch_t* invpbak2; // plain popup background
+static patch_t* invcursor; // cursor
+
+// ammo/weapon/armor patches
+static patch_t* invammo[NUMAMMO]; // ammo/weapons
+static patch_t* invsigil[5]; // sigil pieces
+static patch_t* invarmor[2]; // armor icons
+
+// names for ammo patches
+static char *invammonames[NUMAMMO] =
+{
+ "I_BLIT",
+ "I_XQRL",
+ "I_PQRL",
+ "I_BRY1",
+ "I_ROKT",
+ "I_GRN1",
+ "I_GRN2"
+};
+
+// haleyjd 09/01/10: [STRIFE] Replaced tallnum, shortnum w/inv fonts
+// 0-9, green numbers
+static patch_t* invfontg[10];
+
+// 0-9, yellow numbers
+static patch_t* invfonty[10];
+
+// 3 key-cards, 3 skulls -- [STRIFE] has a lot more keys than 3 :P
+static patch_t* keys[NUMCARDS];
+
+// ready-weapon widget
+static st_number_t w_ready; // haleyjd [STRIFE]: This is still used.
+
+// haleyjd: [STRIFE] This is still used but was changed to a st_number_t.
+// health widget
+static st_number_t w_health;
+
+// ammo widgets
+static st_number_t w_ammo[NUMAMMO]; // haleyjd [STRIFE]: Still used.
+
+// max ammo widgets
+static st_number_t w_maxammo[NUMAMMO]; // haleyjd [STRIFE]: Still used.
+
+// number of frags so far in deathmatch
+static int st_fragscount;
+
+
+cheatseq_t cheat_mus = CHEAT("spin", 2); // [STRIFE]: idmus -> spin
+cheatseq_t cheat_god = CHEAT("omnipotent", 0); // [STRIFE]: iddqd -> omnipotent
+cheatseq_t cheat_ammo = CHEAT("boomstix", 0); // [STRIFE]: idfa -> boomstix
+cheatseq_t cheat_noclip = CHEAT("elvis", 0); // [STRIFE]: idclip -> elvis
+cheatseq_t cheat_clev = CHEAT("rift", 2); // [STRIFE]: idclev -> rift
+cheatseq_t cheat_mypos = CHEAT("gps", 0); // [STRIFE]: idmypos -> gps
+cheatseq_t cheat_scoot = CHEAT("scoot", 1); // [STRIFE]: new cheat scoot
+cheatseq_t cheat_nuke = CHEAT("stonecold", 0); // [STRIFE]: new cheat stonecold
+cheatseq_t cheat_keys = CHEAT("jimmy", 0); // [STRIFE]: new cheat jimmy (all keys)
+cheatseq_t cheat_stealth = CHEAT("gripper", 0); // [STRIFE]: new cheat gripper
+cheatseq_t cheat_midas = CHEAT("donnytrump", 0); // [STRIFE]: new cheat
+cheatseq_t cheat_lego = CHEAT("lego", 0); // [STRIFE]: new cheat
+cheatseq_t cheat_dev = CHEAT("dots", 0); // [STRIFE]: new cheat
+
+// haleyjd 20110224: enumeration for access to powerup cheats
+enum
+{
+ ST_PUMPUP_B,
+ ST_PUMPUP_I,
+ ST_PUMPUP_M,
+ ST_PUMPUP_H,
+ ST_PUMPUP_P,
+ ST_PUMPUP_S,
+ ST_PUMPUP_T,
+ ST_PUMPUP,
+ NUM_ST_PUMPUP
+};
+
+cheatseq_t cheat_powerup[NUM_ST_PUMPUP] = // [STRIFE]
+{
+ CHEAT("pumpupb", 0),
+ CHEAT("pumpupi", 0),
+ CHEAT("pumpupm", 0),
+ CHEAT("pumpuph", 0),
+ CHEAT("pumpupp", 0),
+ CHEAT("pumpups", 0),
+ CHEAT("pumpupt", 0),
+ CHEAT("pumpup", 0),
+};
+
+//cheatseq_t cheat_choppers = CHEAT("idchoppers", 0); [STRIFE] no such thing
+
+void M_SizeDisplay(int choice); // villsa [STRIFE]
+
+//
+// STATUS BAR CODE
+//
+void ST_Stop(void);
+
+// [STRIFE]
+static char st_msgbuf[ST_MSGWIDTH];
+
+// Respond to keyboard input events,
+// intercept cheats.
+boolean ST_Responder(event_t* ev)
+{
+ // haleyjd 09/27/10: made static to ST_Responder
+ static boolean st_keystate = false;
+ int i;
+
+ // Filter automap on/off.
+ if(ev->type == ev_keyup)
+ {
+ if((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;
+ }
+
+ return false;
+ }
+
+ // villsa [STRIFE]
+ if(ev->data1 != key_invpop &&
+ ev->data1 != key_mission &&
+ ev->data1 != key_invkey)
+ return false;
+
+ // villsa [STRIFE]
+ if(ev->data1 == key_invpop)
+ st_showinvpop = false;
+ else
+ {
+ if(ev->data1 == key_mission)
+ st_showobjective = false;
+ else
+ {
+ if(ev->data1 == key_invkey)
+ {
+ st_showkeys = false;
+ st_keystate = false;
+ }
+ }
+ }
+
+ if(!st_showkeys && !st_showobjective && !st_showinvpop)
+ {
+ if(!st_popupdisplaytics)
+ {
+ st_displaypopup = false;
+ if(st_dosizedisplay)
+ M_SizeDisplay(true);
+
+ st_dosizedisplay = false;
+ }
+ }
+
+ return true;
+ }
+
+ // if a user keypress...
+ if(ev->type != ev_keydown)
+ return false;
+
+ // haleyjd 09/27/10: No input allowed when the player is dead
+ if(plyr->mo->health <= 0)
+ return false;
+
+ // keydown events
+ if(ev->data1 == key_invquery) // inventory query
+ {
+ inventory_t *inv = &(plyr->inventory[plyr->inventorycursor]);
+ if(inv->amount)
+ {
+ DEH_snprintf(st_msgbuf, sizeof(st_msgbuf), "%d %s",
+ inv->amount,
+ DEH_String(mobjinfo[inv->type].name));
+ plyr->message = st_msgbuf;
+ }
+ }
+
+ // villsa [STRIFE]
+ if(ev->data1 == key_invpop || ev->data1 == key_invkey || ev->data1 == key_mission)
+ {
+ if(ev->data1 == key_invkey)
+ {
+ st_showobjective = false;
+ st_showinvpop = false;
+
+ if(!st_keystate)
+ {
+ st_keystate = true;
+ if(++st_keypage > 2)
+ {
+ st_popupdisplaytics = 0;
+ st_showkeys = false;
+ st_displaypopup = false;
+ st_keypage = -1;
+ return true;
+ }
+ }
+
+ if(netgame)
+ st_popupdisplaytics = 20;
+ else
+ st_popupdisplaytics = 50;
+
+ st_showkeys = true;
+ }
+ else
+ {
+ if(ev->data1 != key_mission || netgame)
+ {
+ if(ev->data1 == key_invpop)
+ {
+ st_keypage = -1;
+ st_popupdisplaytics = false;
+ st_showkeys = false;
+ st_showobjective = false;
+ st_showinvpop = true;
+ }
+ }
+ else
+ {
+ st_showkeys = netgame;
+ st_showinvpop = netgame;
+ st_keypage = -1;
+
+ st_popupdisplaytics = ev->data2 ^ key_mission;
+
+ st_showobjective = true;
+ }
+ }
+
+ if(st_showkeys || st_showobjective || st_showinvpop)
+ {
+ st_displaypopup = true;
+ if(viewheight == SCREENHEIGHT)
+ {
+ M_SizeDisplay(false);
+ st_dosizedisplay = true;
+ }
+ }
+ }
+
+ if(ev->data1 == key_invleft) // inventory move left
+ {
+ if(plyr->inventorycursor > 0)
+ plyr->inventorycursor--;
+ return true;
+ }
+ else if(ev->data1 == key_invright)
+ {
+ if(plyr->inventorycursor < plyr->numinventory - 1)
+ plyr->inventorycursor++;
+ return true;
+ }
+ else if(ev->data1 == key_invhome)
+ {
+ plyr->inventorycursor = 0;
+ return true;
+ }
+ else if(ev->data1 == key_invend)
+ {
+ if(plyr->numinventory)
+ plyr->inventorycursor = plyr->numinventory - 1;
+ else
+ plyr->inventorycursor = 0;
+ return true;
+ }
+
+ //
+ // [STRIFE] Cheats which are allowed in netgames/demos:
+ //
+
+ // 'spin' cheat for changing music
+ if (cht_CheckCheat(&cheat_mus, ev->data2))
+ {
+ char buf[3];
+ int musnum;
+
+ plyr->message = DEH_String(STSTR_MUS);
+ cht_GetParam(&cheat_mus, buf);
+
+ musnum = (buf[0] - '0') * 10 + buf[1] - '0';
+
+ if (((buf[0]-'0')*10 + buf[1]-'0') > 35)
+ plyr->message = DEH_String(STSTR_NOMUS);
+ else
+ S_ChangeMusic(musnum, 1);
+ }
+ // [STRIFE]: "dev" cheat - "DOTS"
+ else if (cht_CheckCheat(&cheat_dev, ev->data2))
+ {
+ devparm = !devparm;
+ if (devparm)
+ plyr->message = DEH_String("devparm ON");
+ else
+ plyr->message = DEH_String("devparm OFF");
+ }
+
+ // [STRIFE] Cheats below are not allowed in netgames or demos
+ if(netgame || !usergame)
+ return false;
+
+ if (cht_CheckCheat(&cheat_god, ev->data2))
+ {
+ // 'omnipotent' cheat for toggleable god mode
+ plyr->cheats ^= CF_GODMODE;
+ if (plyr->cheats & CF_GODMODE)
+ {
+ if (plyr->mo)
+ plyr->mo->health = 100;
+
+ plyr->health = deh_god_mode_health;
+ plyr->st_update = true; // [STRIFE]
+ plyr->message = DEH_String(STSTR_DQDON);
+ }
+ else
+ {
+ plyr->st_update = true;
+ plyr->message = DEH_String(STSTR_DQDOFF);
+ }
+ }
+ else if (cht_CheckCheat(&cheat_ammo, ev->data2))
+ {
+ // [STRIFE]: "BOOMSTIX" cheat for all normal weapons
+ plyr->armorpoints = deh_idkfa_armor;
+ plyr->armortype = deh_idkfa_armor_class;
+
+ for (i = 0; i < NUMWEAPONS; i++)
+ if(!isdemoversion || weaponinfo[i].availabledemo)
+ plyr->weaponowned[i] = true;
+
+ // Takes away the Sigil, even if you already had it...
+ plyr->weaponowned[wp_sigil] = false;
+
+ for (i=0;i<NUMAMMO;i++)
+ plyr->ammo[i] = plyr->maxammo[i];
+
+ plyr->message = DEH_String(STSTR_FAADDED);
+ }
+ else if(cht_CheckCheat(&cheat_keys, ev->data2))
+ {
+ // villsa [STRIFE]: "JIMMY" cheat for all keys
+ #define FIRSTKEYSETAMOUNT 16
+
+ if(plyr->cards[FIRSTKEYSETAMOUNT - 1])
+ {
+ if(plyr->cards[NUMCARDS - 1] || isdemoversion)
+ {
+ for(i = 0; i < NUMCARDS; i++)
+ plyr->cards[i] = false;
+
+ plyr->message = DEH_String("Keys removed");
+ }
+ else
+ {
+ for(i = 0; i < NUMCARDS; i++)
+ plyr->cards[i] = true;
+
+ plyr->message = DEH_String("Cheater Keys Added");
+ }
+ }
+ else
+ {
+ for(i = 0; i < FIRSTKEYSETAMOUNT; i++)
+ plyr->cards[i] = true;
+
+ plyr->message = DEH_String("Cheater Keys Added");
+ }
+ }
+ else if (cht_CheckCheat(&cheat_noclip, ev->data2))
+ {
+ // [STRIFE] Removed idspispopd, added NOCLIP flag setting/removal
+ // Noclip cheat - "ELVIS" (hah-hah :P )
+
+ plyr->cheats ^= CF_NOCLIP;
+
+ if (plyr->cheats & CF_NOCLIP)
+ {
+ plyr->message = DEH_String(STSTR_NCON);
+ plyr->mo->flags |= MF_NOCLIP;
+ }
+ else
+ {
+ plyr->message = DEH_String(STSTR_NCOFF);
+ plyr->mo->flags &= ~MF_NOCLIP;
+ }
+ }
+ else if(cht_CheckCheat(&cheat_stealth, ev->data2))
+ {
+ // villsa [STRIFE]: "GRIPPER" cheat; nothing to do with stealth...
+ plyr->cheats ^= CF_NOMOMENTUM;
+ if(plyr->cheats & CF_NOMOMENTUM)
+ plyr->message = DEH_String("STEALTH BOOTS ON");
+ else
+ plyr->message = DEH_String("STEALTH BOOTS OFF");
+ }
+
+ for(i = 0; i < ST_PUMPUP_B + 3; ++i)
+ {
+ // [STRIFE]: Handle berserk, invisibility, and envirosuit
+ if(cht_CheckCheat(&cheat_powerup[i], ev->data2))
+ {
+ if(plyr->powers[i])
+ plyr->powers[i] = (i != 1);
+ else
+ P_GivePower(plyr, i);
+ plyr->message = DEH_String(STSTR_BEHOLDX);
+ }
+ }
+ if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_H], ev->data2))
+ {
+ // [STRIFE]: PUMPUPH gives medical inventory items
+ P_GiveItemToPlayer(plyr, SPR_STMP, MT_INV_MED1);
+ P_GiveItemToPlayer(plyr, SPR_MDKT, MT_INV_MED2);
+ P_GiveItemToPlayer(plyr, SPR_FULL, MT_INV_MED3);
+ plyr->message = DEH_String("you got the stuff!");
+ }
+ if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_P], ev->data2))
+ {
+ // [STRIFE]: PUMPUPP gives backpack
+ if(!plyr->backpack)
+ {
+ for(i = 0; i < NUMAMMO; ++i)
+ plyr->maxammo[i] = 2 * plyr->maxammo[i];
+ }
+ plyr->backpack = true;
+
+ for(i = 0; i < NUMAMMO; ++i)
+ P_GiveAmmo(plyr, i, 1);
+ plyr->message = DEH_String("you got the stuff!");
+ }
+ if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_S], ev->data2))
+ {
+ // [STRIFE]: PUMPUPS gives stamina and accuracy upgrades
+ P_GiveItemToPlayer(plyr, SPR_TOKN, MT_TOKEN_STAMINA);
+ P_GiveItemToPlayer(plyr, SPR_TOKN, MT_TOKEN_NEW_ACCURACY);
+ plyr->message = DEH_String("you got the stuff!");
+ }
+ if(cht_CheckCheat(&cheat_powerup[ST_PUMPUP_T], ev->data2))
+ {
+ // [STRIFE] PUMPUPT gives targeter
+ P_GivePower(plyr, pw_targeter);
+ plyr->message = DEH_String("you got the stuff!");
+ }
+ // [STRIFE]: PUMPUP
+ if (cht_CheckCheat(&cheat_powerup[ST_PUMPUP], ev->data2))
+ {
+ // 'behold' power-up menu
+ plyr->message = DEH_String(STSTR_BEHOLD);
+ return false;
+ }
+
+ if (cht_CheckCheat(&cheat_mypos, ev->data2))
+ {
+ // [STRIFE] 'GPS' for player position
+ static char buf[ST_MSGWIDTH];
+ sprintf(buf, "ang=0x%x;x,y=(0x%x,0x%x)",
+ players[consoleplayer].mo->angle,
+ players[consoleplayer].mo->x,
+ players[consoleplayer].mo->y);
+ plyr->message = buf;
+ }
+
+ // 'rift' change-level cheat
+ if (cht_CheckCheat(&cheat_clev, ev->data2))
+ {
+ char buf[3];
+ int map;
+
+ cht_GetParam(&cheat_clev, buf);
+
+ map = (buf[0] - '0') * 10 + buf[1] - '0';
+
+ // haleyjd 09/01/10: Removed Chex Quest stuff.
+ // haleyjd 09/15/10: Removed retail/registered/shareware stuff
+
+ // haleyjd 20130301: different bounds in v1.31
+ // Ohmygod - this is not going to work.
+ if(gameversion == exe_strife_1_31)
+ {
+ if ((isdemoversion && (map < 32 || map > 34)) ||
+ (isregistered && (map <= 0 || map > 34)))
+ return false;
+ }
+ else
+ {
+ if (map <= 0 || map > 40)
+ return false;
+ }
+
+ // So be it.
+ plyr->message = DEH_String(STSTR_CLEV);
+ G_RiftExitLevel(map, 0, plyr->mo->angle);
+ }
+ else if(cht_CheckCheat(&cheat_scoot, ev->data2))
+ {
+ char buf[3];
+ int spot;
+
+ cht_GetParam(&cheat_scoot, buf);
+
+ spot = buf[0] - '0';
+
+ // BUG: should be <= 9. Shouldn't do anything bad though...
+ if(spot <= 10)
+ {
+ plyr->message = DEH_String("Spawning to spot");
+ G_RiftCheat(spot);
+ return false;
+ }
+ }
+
+ // villsa [STRIFE]
+ if(cht_CheckCheat(&cheat_nuke, ev->data2))
+ {
+ stonecold ^= 1;
+ plyr->message = DEH_String("Kill 'em. Kill 'em All");
+ return false;
+ }
+
+ // villsa [STRIFE]
+ if(cht_CheckCheat(&cheat_midas, ev->data2))
+ {
+ plyr->message = DEH_String("YOU GOT THE MIDAS TOUCH, BABY");
+ P_GiveItemToPlayer(plyr, SPR_HELT, MT_TOKEN_TOUGHNESS);
+ }
+
+ // villsa [STRIFE]
+ // haleyjd 20110224: No sigil in demo version
+ if(!isdemoversion && cht_CheckCheat(&cheat_lego, ev->data2))
+ {
+ plyr->st_update = true;
+ if(plyr->weaponowned[wp_sigil])
+ {
+ if(++plyr->sigiltype > 4)
+ {
+ plyr->sigiltype = -1;
+ plyr->pendingweapon = wp_fist;
+ plyr->weaponowned[wp_sigil] = false;
+ }
+ }
+ else
+ {
+ plyr->weaponowned[wp_sigil] = true;
+ plyr->sigiltype = 0;
+ }
+ // BUG: This brings up a bad version of the Sigil (sigiltype -1) which
+ // causes some VERY interesting behavior, when you type LEGO for the
+ // sixth time. This shouldn't be done when taking it away, and yet it
+ // is here... verified with vanilla.
+ plyr->pendingweapon = wp_sigil;
+ }
+
+ return false;
+}
+
+
+/*
+int ST_calcPainOffset(void)
+{
+ // haleyjd 08/31/10: [STRIFE] Removed.
+}
+*/
+
+//
+// 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)
+{
+ // haleyjd 08/31/10: [STRIFE] Removed.
+}
+*/
+
+/*
+void ST_updateWidgets(void)
+{
+ // haleyjd 09/01/10: [STRIFE] Rogue merged this into ST_Ticker below.
+}
+*/
+
+//
+// ST_Ticker
+//
+// haleyjd 09/01/10: [STRIFE]
+// * Removed st_clock and st_randomnumber.
+// * Merged ST_updateWidgets here. Wasn't inlined, as doesn't exist separately
+// in the binary as inlined functions normally do.
+//
+void ST_Ticker (void)
+{
+ static int largeammo = 1994; // means "n/a"
+
+ // must redirect the pointer if the ready weapon has changed.
+ if (weaponinfo[plyr->readyweapon].ammo == am_noammo)
+ w_ready.num = &largeammo;
+ else
+ w_ready.num = &plyr->ammo[weaponinfo[plyr->readyweapon].ammo];
+
+ w_ready.data = plyr->readyweapon;
+
+ // STRIFE-TODO: Gobbledeegunk.
+ /*
+ v2 = dword_88490-- == 1; // no clue yet...
+ if(v2)
+ dword_DC7F4 = dword_DC7F0;*/
+
+ if(st_popupdisplaytics)
+ {
+ int tics = st_popupdisplaytics;
+
+ --st_popupdisplaytics;
+ if(tics == 1)
+ {
+ st_displaypopup = false;
+ st_showkeys = false;
+ st_keypage = -1;
+
+ if(st_dosizedisplay)
+ M_SizeDisplay(true); // mondo hack?
+
+ st_dosizedisplay = false;
+ }
+ }
+
+ // haleyjd 09/01/10: [STRIFE] Keys are handled on a popup
+ // haleyjd 08/31/10: [STRIFE] No face widget
+ // haleyjd 09/01/10: [STRIFE] Armor, weapons, frags, etc. handled elsewhere
+
+ // haleyjd: This is from the PRE-BETA! Left here because it amuses me ;)
+ // get rid of chat window if up because of message
+ //if (!--st_msgcounter)
+ // st_chat = st_oldchat;
+}
+
+static int st_palette = 0;
+
+//
+// ST_doPaletteStuff
+//
+// haleyjd 08/31/10: [STRIFE]
+// * Changed radsuit palette handling for Strife nukagecount.
+// * All other logic verified to be unmodified.
+//
+void ST_doPaletteStuff(void)
+{
+
+ int palette;
+ byte* pal;
+ int cnt;
+ int bzc;
+
+ cnt = plyr->damagecount;
+
+ if (plyr->powers[pw_strength])
+ {
+ // slowly fade the berzerk out
+ 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;
+ }
+ // haleyjd 08/31/10: [STRIFE] Flash green when in nukage, not when has
+ // an environment suit (a breathing sound is played to indicate that
+ // instead).
+ else if ( plyr->nukagecount > 16*TICRATE ||
+ (plyr->nukagecount & 8))
+ palette = RADIATIONPAL;
+ else
+ palette = 0;
+
+ // haleyjd 08/31/10: Removed Chex Quest
+
+ if (palette != st_palette)
+ {
+ st_palette = palette;
+ pal = (byte *) W_CacheLumpNum (lu_palette, PU_CACHE)+palette*768;
+ I_SetPalette (pal);
+ }
+
+}
+
+/*
+void ST_drawWidgets(boolean refresh)
+{
+ haleyjd 09/01/10: [STRIFE] Removed
+}
+*/
+
+//
+// ST_drawNumFontY
+//
+// haleyjd 09/19/10: [STRIFE] New function
+// Draws a small yellow number for inventory etc.
+//
+void ST_drawNumFontY(int x, int y, int num)
+{
+ if(!num)
+ V_DrawPatch(x, y, invfonty[0]);
+
+ while(num)
+ {
+ V_DrawPatch(x, y, invfonty[num % 10]);
+ x -= SHORT(invfonty[0]->width) + 1;
+ num /= 10;
+ }
+}
+
+//
+// ST_drawNumFontY2
+//
+// haleyjd 09/19/10: [STRIFE] New function
+// As above, but turns negative numbers into zero.
+//
+void ST_drawNumFontY2(int x, int y, int num)
+{
+ if(!num)
+ V_DrawPatch(x, y, invfonty[0]);
+
+ if(num < 0)
+ num = 0;
+
+ while(num)
+ {
+ V_DrawPatchDirect(x, y, invfonty[num % 10]);
+ x -= SHORT(invfonty[0]->width) + 1;
+ num /= 10;
+ }
+}
+
+//
+// ST_drawLine
+//
+// haleyjd 09/20/10: [STRIFE] New function
+// Basic horizontal line drawing routine used for the health bars.
+//
+void ST_drawLine(int x, int y, int len, int color)
+{
+ byte putcolor = (byte)(color);
+ byte *drawpos = I_VideoBuffer + y * SCREENWIDTH + x;
+ int i = 0;
+
+ while(i < len)
+ {
+ *drawpos++ = putcolor;
+ ++i;
+ }
+}
+
+//
+// ST_doRefresh
+//
+// haleyjd 09/20/10: Evidence more than suggests that Rogue moved all status bar
+// drawing down to this function.
+//
+void ST_doRefresh(void)
+{
+ // draw status bar background to off-screen buff
+ if (st_statusbaron)
+ {
+ int firstinventory, icon_x, num_x, i, numdrawn;
+
+ // haleyjd 09/19/10: No backscreen caching in Strife.
+ //V_UseBuffer(st_backing_screen);
+
+ // TODO: only sometimes drawing?
+
+ plyr->st_update = false;
+
+ // cache data
+ st_lastcursorpos = plyr->inventorycursor;
+ st_lastammo = weaponinfo[plyr->readyweapon].ammo;
+ st_lastarmortype = plyr->armortype;
+ st_lasthealth = plyr->health;
+ st_firsttime = false;
+
+ // draw main status bar
+ V_DrawPatch(ST_X, ST_Y, invback);
+
+ // draw multiplayer armor backdrop if netgame
+ if(netgame)
+ V_DrawPatch(ST_X, 173, stback);
+
+ if(plyr->inventorycursor >= 6)
+ firstinventory = plyr->inventorycursor - 5;
+ else
+ firstinventory = 0;
+
+ // Draw cursor.
+ if(plyr->numinventory)
+ {
+ V_DrawPatch(35 * (plyr->inventorycursor - firstinventory) + 42,
+ 180, invcursor);
+ }
+
+ // Draw inventory bar
+ for(num_x = 68, icon_x = 48, i = firstinventory, numdrawn = 0;
+ num_x < 278;
+ num_x += 35, icon_x += 35, i++, numdrawn++)
+ {
+ int lumpnum;
+ patch_t *patch;
+ char iconname[8];
+
+ if(plyr->numinventory <= numdrawn)
+ break;
+
+ DEH_snprintf(iconname, sizeof(iconname), "I_%s",
+ DEH_String(sprnames[plyr->inventory[i].sprite]));
+
+ lumpnum = W_CheckNumForName(iconname);
+ if(lumpnum == -1)
+ patch = W_CacheLumpName(DEH_String("STCFN063"), PU_CACHE);
+ else
+ patch = W_CacheLumpNum(lumpnum, PU_STATIC);
+
+ V_DrawPatch(icon_x, 182, patch);
+ ST_drawNumFontY(num_x, 191, plyr->inventory[i].amount);
+ }
+
+ // haleyjd 09/19/10: Draw sigil icon
+ if(plyr->weaponowned[wp_sigil])
+ V_DrawPatch(253, 175, invsigil[plyr->sigiltype]);
+
+ // haleyjd 09/19/10: Draw ammo
+ if(st_lastammo < NUMAMMO)
+ V_DrawPatch(290, 180, invammo[st_lastammo]);
+
+ // haleyjd 09/19/10: Draw armor
+ if(plyr->armortype)
+ {
+ V_DrawPatch(2, 177, invarmor[plyr->armortype - 1]);
+ ST_drawNumFontY(20, 191, plyr->armorpoints);
+ }
+
+ // haleyjd 09/20/10: Draw life bars.
+ {
+ int barlength;
+ int lifecolor1;
+ int lifecolor2;
+
+ barlength = plyr->health;
+ if(barlength > 100)
+ barlength = 200 - plyr->health;
+ barlength *= 2;
+
+ if(plyr->health < 11) // Danger, Will Robinson!
+ lifecolor1 = 64;
+ else if(plyr->health < 21) // Caution
+ lifecolor1 = 80;
+ else // All is well.
+ lifecolor1 = 96;
+
+ if(plyr->cheats & CF_GODMODE) // Gold, probably a throwback to DOOM.
+ lifecolor1 = 226;
+
+ lifecolor2 = lifecolor1 + 3;
+
+ // Draw the normal health bars
+ ST_drawLine(49, 172, barlength, lifecolor1);
+ ST_drawLine(49, 173, barlength, lifecolor2);
+ ST_drawLine(49, 175, barlength, lifecolor1);
+ ST_drawLine(49, 176, barlength, lifecolor2);
+
+ // Draw the > 100 health lines
+ if(plyr->health > 100)
+ {
+ int oldbarlength = barlength;
+ lifecolor1 = 112; // Shades of blue
+ lifecolor2 = lifecolor1 + 3;
+
+ // take up the difference not drawn by the first (<= 100) bar
+ barlength = 200 - barlength;
+
+ ST_drawLine(49 + oldbarlength, 172, barlength, lifecolor1);
+ ST_drawLine(49 + oldbarlength, 173, barlength, lifecolor2);
+ ST_drawLine(49 + oldbarlength, 175, barlength, lifecolor1);
+ ST_drawLine(49 + oldbarlength, 176, barlength, lifecolor2);
+ }
+ } // end local-scope block
+
+ // haleyjd 09/19/10: nope, not in Strife.
+ //V_RestoreBuffer();
+ //V_CopyRect(ST_X, 0, st_backing_screen, ST_WIDTH, ST_HEIGHT, ST_X, ST_Y);
+ }
+}
+
+// haleyjd [STRIFE]: Removed ST_diffDraw
+
+void ST_Drawer (boolean fullscreen, boolean refresh)
+{
+ st_statusbaron = (!fullscreen) || automapactive;
+ st_firsttime = st_firsttime || refresh;
+
+ // Do red-/gold-shifts from damage/items
+ ST_doPaletteStuff();
+
+ // If just after ST_Start(), refresh all
+ ST_doRefresh();
+ // Otherwise, update as little as possible
+ //ST_diffDraw(); [STRIFE]: nope
+}
+
+//
+// ST_drawTime
+//
+// villsa [STRIFE] New function.
+// Draws game time on pop up screen
+//
+static void ST_drawTime(int x, int y, int time)
+{
+ int hours;
+ int minutes;
+ int seconds;
+ char string[16];
+
+ // haleyjd 20110213: fixed minutes
+ hours = time / 3600;
+ minutes = (time / 60) % 60;
+ seconds = time % 60;
+
+ DEH_snprintf(string, 16, "%02d:%02d:%02d", hours, minutes, seconds);
+ HUlib_drawYellowText(x, y, string);
+}
+
+#define ST_KEYSPERPAGE 10
+#define ST_KEYS_X 20
+#define ST_KEYS_Y 63
+#define ST_KEYNAME_X 17
+#define ST_KEYNAME_Y 4
+#define ST_KEYS_YSTEP 17
+#define ST_KEYS_NUMROWS 4
+#define ST_KEYS_COL2X 160
+
+//
+// ST_drawKeysPopup
+//
+// haleyjd 20110213: [STRIFE] New function
+// This has taken the longest out of almost everything to get working properly.
+//
+static boolean ST_drawKeysPopup(void)
+{
+ int x, y, key, keycount;
+ mobjinfo_t *info;
+
+ V_DrawXlaPatch(0, 56, invpbak2);
+ V_DrawPatchDirect(0, 56, invpop2);
+
+ if(deathmatch)
+ {
+ // STRIFE-TODO: In deathmatch, the keys popup is replaced by a chart
+ // of frag counts
+ }
+ else
+ {
+ // Bounds-check page number
+ if(st_keypage < 0 || st_keypage > 2)
+ {
+ st_keypage = -1;
+ st_popupdisplaytics = 0;
+ st_displaypopup = false;
+
+ return false;
+ }
+
+ // Are there any keys to display on this page?
+ if(st_keypage > 0)
+ {
+ boolean haskeyinrange = false;
+
+ for(key = ST_KEYSPERPAGE * st_keypage, keycount = 0;
+ keycount < ST_KEYSPERPAGE && key < NUMCARDS;
+ ++key, ++keycount)
+ {
+ if(plyr->cards[key])
+ haskeyinrange = true;
+ }
+
+ if(!haskeyinrange)
+ {
+ st_displaypopup = false;
+ st_showkeys = false;
+ st_keypage = -1;
+
+ return false;
+ }
+ }
+
+ // Draw the keys for the current page
+ key = ST_KEYSPERPAGE * st_keypage;
+ keycount = 0;
+ x = ST_KEYS_X;
+ y = ST_KEYS_Y;
+ info = &mobjinfo[MT_KEY_BASE + key];
+
+ for(; keycount < ST_KEYSPERPAGE && key < NUMCARDS; ++key, ++keycount, ++info)
+ {
+ char sprname[8];
+ patch_t *patch;
+ memset(sprname, 0, sizeof(sprname));
+
+ if(plyr->cards[key])
+ {
+ // Get spawnstate sprite name and load corresponding icon
+ DEH_snprintf(sprname, sizeof(sprname), "I_%s",
+ sprnames[states[info->spawnstate].sprite]);
+ patch = W_CacheLumpName(sprname, PU_CACHE);
+ V_DrawPatchDirect(x, y, patch);
+ HUlib_drawYellowText(x + ST_KEYNAME_X, y + ST_KEYNAME_Y, info->name);
+ }
+
+ if(keycount != ST_KEYS_NUMROWS)
+ y += ST_KEYS_YSTEP;
+ else
+ {
+ x = ST_KEYS_COL2X;
+ y = ST_KEYS_Y;
+ }
+ }
+ }
+
+ return true;
+}
+
+//
+// ST_DrawExternal
+//
+// haleyjd 09/01/10: [STRIFE] New function.
+// * Draws external portions of the status bar such the top bar and popups.
+//
+boolean ST_DrawExternal(void)
+{
+ int i;
+
+ if(st_statusbaron)
+ {
+ V_DrawPatchDirect(0, 160, invtop);
+ STlib_drawNumPositive(&w_health);
+ STlib_drawNumPositive(&w_ready);
+ }
+ else
+ {
+ ammotype_t ammo;
+
+ ST_drawNumFontY2(15, 194, plyr->health);
+ ammo = weaponinfo[plyr->readyweapon].ammo;
+ if (ammo != am_noammo)
+ ST_drawNumFontY2(310, 194, plyr->ammo[ammo]);
+ }
+
+ if(!st_displaypopup)
+ return false;
+
+ // villsa [STRIFE] added 09/26/10
+ if(st_showobjective)
+ {
+ V_DrawXlaPatch(0, 56, invpbak2);
+ V_DrawPatchDirect(0, 56, invpop2);
+ M_DialogDimMsg(24, 74, mission_objective, true);
+ HUlib_drawYellowText(24, 74, mission_objective);
+ ST_drawTime(210, 64, leveltime / TICRATE);
+ }
+ else
+ {
+ int keys = 0;
+
+ // villsa [STRIFE] keys popup
+ if(st_showkeys || st_popupdisplaytics)
+ return ST_drawKeysPopup();
+
+ V_DrawXlaPatch(0, 56, invpbak);
+ V_DrawPatchDirect(0, 56, invpop);
+
+ for(i = 0; i < NUMCARDS; i++)
+ {
+ if(plyr->cards[i])
+ keys++;
+ }
+
+ ST_drawNumFontY2(261, 132, keys);
+
+ if(plyr->weaponowned[wp_elecbow])
+ {
+ V_DrawPatchDirect(38, 86,
+ W_CacheLumpName(DEH_String("CBOWA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_rifle])
+ {
+ V_DrawPatchDirect(40, 107,
+ W_CacheLumpName(DEH_String("RIFLA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_missile])
+ {
+ V_DrawPatchDirect(39, 131,
+ W_CacheLumpName(DEH_String("MMSLA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_hegrenade])
+ {
+ V_DrawPatchDirect(78, 87,
+ W_CacheLumpName(DEH_String("GRNDA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_flame])
+ {
+ V_DrawPatchDirect(80, 117,
+ W_CacheLumpName(DEH_String("FLAMA0"), PU_CACHE));
+ }
+ if(plyr->weaponowned[wp_mauler])
+ {
+ V_DrawPatchDirect(75, 142,
+ W_CacheLumpName(DEH_String("TRPDA0"), PU_CACHE));
+ }
+
+ // haleyjd 20110213: draw ammo
+ for(i = 0; i < NUMAMMO; i++)
+ {
+ STlib_drawNumPositive(&w_ammo[i]);
+ STlib_drawNumPositive(&w_maxammo[i]);
+ }
+
+ ST_drawNumFontY2(261, 84, plyr->accuracy);
+ ST_drawNumFontY2(261, 108, plyr->stamina);
+
+ if(plyr->powers[pw_communicator])
+ {
+ V_DrawPatchDirect(280, 130,
+ W_CacheLumpName(DEH_String("I_COMM"), PU_CACHE));
+ }
+ }
+
+ return true;
+}
+
+typedef void (*load_callback_t)(char *lumpname, patch_t **variable);
+
+//
+// ST_loadUnloadGraphics
+//
+// Iterates through all graphics to be loaded or unloaded, along with
+// the variable they use, invoking the specified callback function.
+//
+// [STRIFE] Altered to load all Strife status bar resources.
+//
+static void ST_loadUnloadGraphics(load_callback_t callback)
+{
+ int i;
+ char namebuf[9];
+
+ // haleyjd 09/01/10: [STRIFE]
+ // Load the numbers, green and yellow
+ for (i=0;i<10;i++)
+ {
+ DEH_snprintf(namebuf, 9, "INVFONG%d", i);
+ callback(namebuf, &invfontg[i]);
+
+ DEH_snprintf(namebuf, 9, "INVFONY%d", i);
+ callback(namebuf, &invfonty[i]);
+ }
+
+ // haleyjd 09/19/10: load Sigil patches
+ if(!isdemoversion)
+ {
+ for(i = 0; i < 5; i++)
+ {
+ DEH_snprintf(namebuf, 9, "I_SGL%d", i+1);
+ callback(namebuf, &invsigil[i]);
+ }
+ }
+
+ // load ammo patches
+ for(i = 0; i < NUMAMMO; i++)
+ callback(DEH_String(invammonames[i]), &invammo[i]);
+
+ // load armor patches
+ callback(DEH_String("I_ARM2"), &invarmor[0]);
+ callback(DEH_String("I_ARM1"), &invarmor[1]);
+
+ // haleyjd 09/19/10: [STRIFE]
+ // * No face, but there is this patch, which appears behind the armor
+ DEH_snprintf(namebuf, 9, "STBACK0%d", consoleplayer + 1);
+ if(netgame)
+ callback(namebuf, &stback);
+
+ // 09/01/10:
+ // * Removed all unused DOOM stuff (arms, numbers, %, etc).
+
+ // haleyjd 09/01/10: [STRIFE]: stbar -> invback, added new patches
+ // status bar background bits
+ callback(DEH_String("INVBACK"), &invback);
+ callback(DEH_String("INVTOP"), &invtop);
+ callback(DEH_String("INVPOP"), &invpop);
+ callback(DEH_String("INVPOP2"), &invpop2);
+ callback(DEH_String("INVPBAK"), &invpbak);
+ callback(DEH_String("INVPBAK2"), &invpbak2);
+ callback(DEH_String("INVCURS"), &invcursor);
+}
+
+static void ST_loadCallback(char *lumpname, patch_t **variable)
+{
+ *variable = W_CacheLumpName(lumpname, PU_STATIC);
+}
+
+void ST_loadGraphics(void)
+{
+ ST_loadUnloadGraphics(ST_loadCallback);
+}
+
+void ST_loadData(void)
+{
+ static int dword_8848C = 1; // STRIFE-TODO: what is the purpose of this?
+ dword_8848C = 0;
+
+ lu_palette = W_GetNumForName (DEH_String("PLAYPAL"));
+ ST_loadGraphics();
+}
+
+static void ST_unloadCallback(char *lumpname, patch_t **variable)
+{
+ W_ReleaseLumpName(lumpname);
+ *variable = NULL;
+}
+
+void ST_unloadGraphics(void)
+{
+ ST_loadUnloadGraphics(ST_unloadCallback);
+}
+
+void ST_unloadData(void)
+{
+ ST_unloadGraphics();
+}
+
+//
+// ST_initData
+//
+// haleyjd 09/01/10: [STRIFE]
+// * Removed prebeta cruft, face stuff, keyboxes, and oldwe
+//
+void ST_initData(void)
+{
+ st_firsttime = true;
+ plyr = &players[consoleplayer];
+
+ st_gamestate = FirstPersonState;
+
+ st_statusbaron = true;
+
+ st_palette = -1;
+
+ STlib_init();
+}
+
+
+
+void ST_createWidgets(void)
+{
+ int i;
+
+ // ready weapon ammo
+ STlib_initNum(&w_ready,
+ ST_AMMOX,
+ ST_AMMOY,
+ invfontg,
+ &plyr->ammo[weaponinfo[plyr->readyweapon].ammo],
+ ST_AMMOWIDTH);
+
+ // the last weapon type
+ w_ready.data = plyr->readyweapon;
+
+ // health percentage
+ STlib_initNum(&w_health,
+ ST_HEALTHX,
+ ST_HEALTHY,
+ invfontg,
+ &plyr->health,
+ ST_HEALTHWIDTH);
+
+ // haleyjd 20100831: [STRIFE]
+ // * No face.
+ // 20100901:
+ // * No arms, weaponsowned, frags, armor, keyboxes
+
+ // haleyjd 20110213: Ammo Widgets!!!
+ for(i = 0; i < NUMAMMO; i++)
+ {
+ STlib_initNum(&w_ammo[i], ST_POPUPAMMOX, st_yforammo[i],
+ invfonty, &plyr->ammo[i], st_wforammo[i]);
+
+ STlib_initNum(&w_maxammo[i], ST_POPUPMAXAMMOX, st_yforammo[i],
+ invfonty, &plyr->maxammo[i], st_wforammo[i]);
+ }
+}
+
+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;
+
+ I_SetPalette (W_CacheLumpNum (lu_palette, PU_CACHE));
+
+ st_stopped = true;
+}
+
+void ST_Init (void)
+{
+ ST_loadData();
+
+ // haleyjd 09/19/10: This is not used by Strife. More memory for voices!
+ //st_backing_screen = (byte *) Z_Malloc(ST_WIDTH * ST_HEIGHT, PU_STATIC, 0);
+}
+
diff --git a/src/strife/st_stuff.h b/src/strife/st_stuff.h
new file mode 100644
index 00000000..2bf3bbd4
--- /dev/null
+++ b/src/strife/st_stuff.h
@@ -0,0 +1,108 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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"
+#include "m_cheat.h"
+
+// Size of statusbar.
+// Now sensitive for scaling.
+#define ST_HEIGHT 32
+#define ST_WIDTH SCREENWIDTH
+#define ST_Y (SCREENHEIGHT - ST_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 fullscreen, boolean refresh);
+
+// haleyjd 09/01/10: [STRIFE] New function.
+// Called by main loop to draw external status bar bits.
+// Returns true if a popup is drawing.
+boolean ST_DrawExternal(void);
+
+// 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;
+
+
+
+extern byte *st_backing_screen;
+
+extern cheatseq_t cheat_mus; // [STRIFE]: idmus -> spin
+extern cheatseq_t cheat_god; // [STRIFE]: iddqd -> omnipotent
+extern cheatseq_t cheat_ammo; // [STRIFE]: idfa -> boomstix
+extern cheatseq_t cheat_noclip; // [STRIFE]: idclip -> elvis
+extern cheatseq_t cheat_clev; // [STRIFE]: idclev -> rift
+extern cheatseq_t cheat_mypos; // [STRIFE]: idmypos -> gps
+extern cheatseq_t cheat_scoot; // [STRIFE]: new cheat scoot
+extern cheatseq_t cheat_nuke; // [STRIFE]: new cheat stonecold
+extern cheatseq_t cheat_keys; // [STRIFE]: new cheat jimmy (all keys)
+extern cheatseq_t cheat_stealth; // [STRIFE]: new cheat gripper
+extern cheatseq_t cheat_midas; // [STRIFE]: new cheat
+extern cheatseq_t cheat_lego; // [STRIFE]: new cheat
+extern cheatseq_t cheat_dev; // [STRIFE]: new cheat
+
+extern cheatseq_t cheat_powerup[];
+
+
+#endif
diff --git a/src/strife/wi_stuff.c b/src/strife/wi_stuff.c
new file mode 100644
index 00000000..f322e31f
--- /dev/null
+++ b/src/strife/wi_stuff.c
@@ -0,0 +1,1844 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+// haleyjd 08/23/2010: There is no intermission in Strife
+#if 0
+#include <stdio.h>
+
+#include "z_zone.h"
+
+#include "m_random.h"
+
+#include "deh_main.h"
+#include "i_swap.h"
+#include "i_system.h"
+
+#include "w_wad.h"
+
+#include "g_game.h"
+
+#include "r_local.h"
+#include "s_sound.h"
+
+#include "doomstat.h"
+
+// Data.
+#include "sounds.h"
+
+// Needs access to LFB.
+#include "v_video.h"
+
+#include "wi_stuff.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
+
+
+// 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
+
+// SINGPLE-PLAYER STUFF
+#define SP_STATSX 50
+#define SP_STATSY 50
+
+#define SP_TIMEX 16
+#define SP_TIMEY (SCREENHEIGHT-32)
+
+
+// NET GAME STUFF
+#define NG_STATSY 50
+#define NG_STATSX (32 + SHORT(star->width)/2 + 32*!dofrags)
+
+#define NG_SPACINGX 64
+
+
+// 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
+
+
+
+
+typedef enum
+{
+ ANIM_ALWAYS,
+ ANIM_RANDOM,
+ ANIM_LEVEL
+
+} animenum_t;
+
+typedef struct
+{
+ int x;
+ 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
+ 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.
+//
+
+#define ANIM(type, period, nanims, x, y, nexttic) \
+ { (type), (period), (nanims), { (x), (y) }, (nexttic), \
+ 0, { NULL, NULL, NULL }, 0, 0, 0, 0 }
+
+
+static anim_t epsd0animinfo[] =
+{
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 224, 104, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 184, 160, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 112, 136, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 72, 112, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 88, 96, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 48, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 192, 40, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 136, 16, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 80, 16, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 64, 24, 0),
+};
+
+static anim_t epsd1animinfo[] =
+{
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 1),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 2),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 3),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 4),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 5),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 6),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 7),
+ ANIM(ANIM_LEVEL, TICRATE/3, 3, 192, 144, 8),
+ ANIM(ANIM_LEVEL, TICRATE/3, 1, 128, 136, 8),
+};
+
+static anim_t epsd2animinfo[] =
+{
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 168, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 40, 136, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 160, 96, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 104, 80, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/3, 3, 120, 32, 0),
+ ANIM(ANIM_ALWAYS, TICRATE/4, 3, 40, 0, 0),
+};
+
+static int NUMANIMS[NUMEPISODES] =
+{
+ arrlen(epsd0animinfo),
+ arrlen(epsd1animinfo),
+ arrlen(epsd2animinfo),
+};
+
+static anim_t *anims[NUMEPISODES] =
+{
+ epsd0animinfo,
+ epsd1animinfo,
+ epsd2animinfo
+};
+
+
+//
+// GENERAL DATA
+//
+
+//
+// Locally used stuff.
+//
+
+// 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
+static int acceleratestage;
+
+// 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_kills[MAXPLAYERS];
+static int cnt_items[MAXPLAYERS];
+static int cnt_secret[MAXPLAYERS];
+static int cnt_time;
+static int cnt_par;
+static int cnt_pause;
+
+// # of commercial levels
+static int NUMCMAPS;
+
+
+//
+// GRAPHICS
+//
+
+// You Are Here graphic
+static patch_t* yah[3] = { NULL, NULL, NULL };
+
+// splat
+static patch_t* splat[2] = { NULL, NULL };
+
+// %, : graphics
+static patch_t* percent;
+static patch_t* colon;
+
+// 0-9 graphic
+static patch_t* num[10];
+
+// minus sign
+static patch_t* wiminus;
+
+// "Finished!" graphics
+static patch_t* finished;
+
+// "Entering" graphic
+static patch_t* entering;
+
+// "secret"
+static patch_t* sp_secret;
+
+ // "Kills", "Scrt", "Items", "Frags"
+static patch_t* kills;
+static patch_t* secret;
+static patch_t* items;
+static patch_t* frags;
+
+// Time sucks.
+static patch_t* timepatch;
+static patch_t* par;
+static patch_t* sucks;
+
+// "killers", "victims"
+static patch_t* killers;
+static patch_t* victims;
+
+// "Total", your face, your dead face
+static patch_t* total;
+static patch_t* star;
+static patch_t* bstar;
+
+// "red P[1..MAXPLAYERS]"
+static patch_t* p[MAXPLAYERS];
+
+// "gray P[1..MAXPLAYERS]"
+static patch_t* bp[MAXPLAYERS];
+
+ // Name graphics of each level (centered)
+static patch_t** lnames;
+
+// Buffer storing the backdrop
+static patch_t *background;
+
+//
+// CODE
+//
+
+// slam background
+void WI_slamBackground(void)
+{
+ V_DrawPatch(0, 0, background);
+}
+
+// The ticker is used to detect keys
+// because of timing issues in netgames.
+boolean WI_Responder(event_t* ev)
+{
+ return false;
+}
+
+
+// Draws "<Levelname> Finished!"
+void WI_drawLF(void)
+{
+ int y = WI_TITLEY;
+
+ if (gamemode != commercial || wbs->last < NUMCMAPS)
+ {
+ // draw <LevelName>
+ V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->last]->width))/2,
+ y, lnames[wbs->last]);
+
+ // draw "Finished!"
+ y += (5*SHORT(lnames[wbs->last]->height))/4;
+
+ V_DrawPatch((SCREENWIDTH - SHORT(finished->width)) / 2, y, finished);
+ }
+ else if (wbs->last == NUMCMAPS)
+ {
+ // MAP33 - nothing is displayed!
+ }
+ else if (wbs->last > NUMCMAPS)
+ {
+ // > MAP33. Doom bombs out here with a Bad V_DrawPatch error.
+ // I'm pretty sure that doom2.exe is just reading into random
+ // bits of memory at this point, but let's try to be accurate
+ // anyway. This deliberately triggers a V_DrawPatch error.
+
+ patch_t tmp = { SCREENWIDTH, SCREENHEIGHT, 1, 1,
+ { 0, 0, 0, 0, 0, 0, 0, 0 } };
+
+ V_DrawPatch(0, y, &tmp);
+ }
+}
+
+
+
+// Draws "Entering <LevelName>"
+void WI_drawEL(void)
+{
+ int y = WI_TITLEY;
+
+ // draw "Entering"
+ V_DrawPatch((SCREENWIDTH - SHORT(entering->width))/2,
+ y,
+ entering);
+
+ // draw level
+ y += (5*SHORT(lnames[wbs->next]->height))/4;
+
+ V_DrawPatch((SCREENWIDTH - SHORT(lnames[wbs->next]->width))/2,
+ y,
+ lnames[wbs->next]);
+
+}
+
+void
+WI_drawOnLnode
+( int n,
+ patch_t* c[] )
+{
+
+ int i;
+ int left;
+ int top;
+ int right;
+ int bottom;
+ boolean fits = false;
+
+ i = 0;
+ do
+ {
+ left = lnodes[wbs->epsd][n].x - SHORT(c[i]->leftoffset);
+ top = lnodes[wbs->epsd][n].y - SHORT(c[i]->topoffset);
+ right = left + SHORT(c[i]->width);
+ bottom = top + SHORT(c[i]->height);
+
+ if (left >= 0
+ && right < SCREENWIDTH
+ && top >= 0
+ && bottom < SCREENHEIGHT)
+ {
+ fits = true;
+ }
+ else
+ {
+ i++;
+ }
+ } while (!fits && i!=2 && c[i] != NULL);
+
+ if (fits && i<2)
+ {
+ V_DrawPatch(lnodes[wbs->epsd][n].x,
+ lnodes[wbs->epsd][n].y,
+ c[i]);
+ }
+ else
+ {
+ // DEBUG
+ printf("Could not place patch on level %d", n+1);
+ }
+}
+
+
+
+void WI_initAnimatedBack(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];
+
+ // 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;
+ }
+
+}
+
+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;
+ }
+ }
+
+ }
+
+}
+
+void WI_drawAnimatedBack(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 (a->ctr >= 0)
+ V_DrawPatch(a->loc.x, a->loc.y, a->p[a->ctr]);
+ }
+
+}
+
+//
+// Draws a number.
+// If digits > 0, then use that many digits minimum,
+// otherwise only use as many as necessary.
+// Returns new x position.
+//
+
+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;
+ V_DrawPatch(x, y, num[ n % 10 ]);
+ n /= 10;
+ }
+
+ // draw a minus sign if necessary
+ if (neg)
+ V_DrawPatch(x-=8, y, wiminus);
+
+ return x;
+
+}
+
+void
+WI_drawPercent
+( int x,
+ int y,
+ int p )
+{
+ if (p < 0)
+ return;
+
+ V_DrawPatch(x, y, percent);
+ WI_drawNum(x, y, p, -1);
+}
+
+
+
+//
+// Display level completion time and par,
+// or "sucks" message if overflow.
+//
+void
+WI_drawTime
+( int x,
+ int y,
+ int t )
+{
+
+ int div;
+ int n;
+
+ if (t<0)
+ return;
+
+ if (t <= 61*59)
+ {
+ div = 1;
+
+ do
+ {
+ n = (t / div) % 60;
+ x = WI_drawNum(x, y, n, 2) - SHORT(colon->width);
+ div *= 60;
+
+ // draw
+ if (div==60 || t / div)
+ V_DrawPatch(x, y, colon);
+
+ } while (t / div);
+ }
+ else
+ {
+ // "sucks"
+ V_DrawPatch(x - SHORT(sucks->width), y, sucks);
+ }
+}
+
+
+void WI_End(void)
+{
+ void WI_unloadData(void);
+ WI_unloadData();
+}
+
+void WI_initNoState(void)
+{
+ state = NoState;
+ acceleratestage = 0;
+ cnt = 10;
+}
+
+void WI_updateNoState(void) {
+
+ WI_updateAnimatedBack();
+
+ if (!--cnt)
+ {
+ // Don't call WI_End yet. G_WorldDone doesnt immediately
+ // change gamestate, so WI_Drawer is still going to get
+ // run until that happens. If we do that after WI_End
+ // (which unloads all the graphics), we're in trouble.
+ //WI_End();
+ G_WorldDone();
+ }
+
+}
+
+static boolean snl_pointeron = false;
+
+
+void WI_initShowNextLoc(void)
+{
+ state = ShowNextLoc;
+ acceleratestage = 0;
+ cnt = SHOWNEXTLOCDELAY * TICRATE;
+
+ WI_initAnimatedBack();
+}
+
+void WI_updateShowNextLoc(void)
+{
+ WI_updateAnimatedBack();
+
+ if (!--cnt || acceleratestage)
+ WI_initNoState();
+ else
+ snl_pointeron = (cnt & 31) < 20;
+}
+
+void WI_drawShowNextLoc(void)
+{
+
+ int i;
+ int last;
+
+ WI_slamBackground();
+
+ // draw animated background
+ WI_drawAnimatedBack();
+
+ if ( gamemode != commercial)
+ {
+ if (wbs->epsd > 2)
+ {
+ WI_drawEL();
+ 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)
+ WI_drawEL();
+
+}
+
+void WI_drawNoState(void)
+{
+ snl_pointeron = true;
+ WI_drawShowNextLoc();
+}
+
+int WI_fragSum(int playernum)
+{
+ int i;
+ int frags = 0;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i]
+ && i!=playernum)
+ {
+ frags += plrs[playernum].frags[i];
+ }
+ }
+
+
+ // JDC hack - negative frags.
+ frags -= plrs[playernum].frags[playernum];
+ // UNUSED if (frags < 0)
+ // frags = 0;
+
+ return frags;
+}
+
+
+
+static int dm_state;
+static int dm_frags[MAXPLAYERS][MAXPLAYERS];
+static int dm_totals[MAXPLAYERS];
+
+
+
+void WI_initDeathmatchStats(void)
+{
+
+ int i;
+ int j;
+
+ state = StatCount;
+ acceleratestage = 0;
+ dm_state = 1;
+
+ cnt_pause = TICRATE;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ for (j=0 ; j<MAXPLAYERS ; j++)
+ if (playeringame[j])
+ dm_frags[i][j] = 0;
+
+ dm_totals[i] = 0;
+ }
+ }
+
+ WI_initAnimatedBack();
+}
+
+
+
+void WI_updateDeathmatchStats(void)
+{
+
+ int i;
+ int j;
+
+ boolean stillticking;
+
+ WI_updateAnimatedBack();
+
+ if (acceleratestage && dm_state != 4)
+ {
+ 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);
+ dm_state = 4;
+ }
+
+
+ if (dm_state == 2)
+ {
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ 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] > 99)
+ dm_frags[i][j] = 99;
+
+ if (dm_frags[i][j] < -99)
+ dm_frags[i][j] = -99;
+
+ stillticking = true;
+ }
+ }
+ dm_totals[i] = WI_fragSum(i);
+
+ if (dm_totals[i] > 99)
+ dm_totals[i] = 99;
+
+ if (dm_totals[i] < -99)
+ dm_totals[i] = -99;
+ }
+
+ }
+ 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;
+ }
+ }
+}
+
+
+
+void WI_drawDeathmatchStats(void)
+{
+
+ int i;
+ int j;
+ int x;
+ int y;
+ int w;
+
+ int lh; // line height
+
+ lh = WI_SPACINGY;
+
+ WI_slamBackground();
+
+ // draw animated background
+ WI_drawAnimatedBack();
+ WI_drawLF();
+
+ // draw stat titles (top line)
+ V_DrawPatch(DM_TOTALSX-SHORT(total->width)/2,
+ DM_MATRIXY-WI_SPACINGY+10,
+ total);
+
+ V_DrawPatch(DM_KILLERSX, DM_KILLERSY, killers);
+ V_DrawPatch(DM_VICTIMSX, DM_VICTIMSY, victims);
+
+ // draw P?
+ x = DM_MATRIXX + DM_SPACINGX;
+ y = DM_MATRIXY;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (playeringame[i])
+ {
+ V_DrawPatch(x-SHORT(p[i]->width)/2,
+ DM_MATRIXY - WI_SPACINGY,
+ p[i]);
+
+ V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
+ y,
+ p[i]);
+
+ if (i == me)
+ {
+ V_DrawPatch(x-SHORT(p[i]->width)/2,
+ DM_MATRIXY - WI_SPACINGY,
+ bstar);
+
+ V_DrawPatch(DM_MATRIXX-SHORT(p[i]->width)/2,
+ y,
+ star);
+ }
+ }
+ else
+ {
+ // V_DrawPatch(x-SHORT(bp[i]->width)/2,
+ // DM_MATRIXY - WI_SPACINGY, bp[i]);
+ // V_DrawPatch(DM_MATRIXX-SHORT(bp[i]->width)/2,
+ // y, bp[i]);
+ }
+ 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;
+ }
+}
+
+static int cnt_frags[MAXPLAYERS];
+static int dofrags;
+static int ng_state;
+
+void WI_initNetgameStats(void)
+{
+
+ int i;
+
+ state = StatCount;
+ acceleratestage = 0;
+ ng_state = 1;
+
+ cnt_pause = TICRATE;
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0;
+
+ dofrags += WI_fragSum(i);
+ }
+
+ dofrags = !!dofrags;
+
+ WI_initAnimatedBack();
+}
+
+
+
+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;
+ cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret;
+
+ if (dofrags)
+ cnt_frags[i] = WI_fragSum(i);
+ }
+ S_StartSound(0, sfx_barexp);
+ ng_state = 10;
+ }
+
+ if (ng_state == 2)
+ {
+ if (!(bcnt&3))
+ S_StartSound(0, sfx_pistol);
+
+ 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;
+ }
+
+ 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;
+
+ if (cnt_secret[i] >= (plrs[i].ssecret * 100) / wbs->maxsecret)
+ cnt_secret[i] = (plrs[i].ssecret * 100) / wbs->maxsecret;
+ 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;
+ }
+ }
+}
+
+
+
+void WI_drawNetgameStats(void)
+{
+ int i;
+ int x;
+ int y;
+ int pwidth = SHORT(percent->width);
+
+ WI_slamBackground();
+
+ // draw animated background
+ WI_drawAnimatedBack();
+
+ WI_drawLF();
+
+ // draw stat titles (top line)
+ V_DrawPatch(NG_STATSX+NG_SPACINGX-SHORT(kills->width),
+ NG_STATSY, kills);
+
+ V_DrawPatch(NG_STATSX+2*NG_SPACINGX-SHORT(items->width),
+ NG_STATSY, items);
+
+ V_DrawPatch(NG_STATSX+3*NG_SPACINGX-SHORT(secret->width),
+ NG_STATSY, secret);
+
+ if (dofrags)
+ V_DrawPatch(NG_STATSX+4*NG_SPACINGX-SHORT(frags->width),
+ NG_STATSY, frags);
+
+ // draw stats
+ y = NG_STATSY + SHORT(kills->height);
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ if (!playeringame[i])
+ continue;
+
+ x = NG_STATSX;
+ V_DrawPatch(x-SHORT(p[i]->width), y, p[i]);
+
+ if (i == me)
+ V_DrawPatch(x-SHORT(p[i]->width), y, star);
+
+ 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;
+ }
+
+}
+
+static int sp_state;
+
+void WI_initStats(void)
+{
+ state = StatCount;
+ acceleratestage = 0;
+ sp_state = 1;
+ cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1;
+ cnt_time = cnt_par = -1;
+ cnt_pause = TICRATE;
+
+ WI_initAnimatedBack();
+}
+
+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;
+ cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret;
+ 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);
+
+ if (cnt_secret[0] >= (plrs[me].ssecret * 100) / wbs->maxsecret)
+ {
+ cnt_secret[0] = (plrs[me].ssecret * 100) / wbs->maxsecret;
+ 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_par += 3;
+
+ if (cnt_par >= wbs->partime / TICRATE)
+ {
+ cnt_par = wbs->partime / TICRATE;
+
+ if (cnt_time >= plrs[me].stime / 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;
+ }
+ }
+
+}
+
+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_DrawPatch(SP_STATSX, SP_STATSY, kills);
+ WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY, cnt_kills[0]);
+
+ V_DrawPatch(SP_STATSX, SP_STATSY+lh, items);
+ WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+lh, cnt_items[0]);
+
+ V_DrawPatch(SP_STATSX, SP_STATSY+2*lh, sp_secret);
+ WI_drawPercent(SCREENWIDTH - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0]);
+
+ V_DrawPatch(SP_TIMEX, SP_TIMEY, timepatch);
+ WI_drawTime(SCREENWIDTH/2 - SP_TIMEX, SP_TIMEY, cnt_time);
+
+ if (wbs->epsd < 3)
+ {
+ V_DrawPatch(SCREENWIDTH/2 + SP_TIMEX, SP_TIMEY, par);
+ WI_drawTime(SCREENWIDTH - SP_TIMEX, SP_TIMEY, cnt_par);
+ }
+
+}
+
+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;
+ }
+ }
+}
+
+
+
+// Updates stuff each tick
+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;
+ }
+
+}
+
+typedef void (*load_callback_t)(char *lumpname, patch_t **variable);
+
+// Common load/unload function. Iterates over all the graphics
+// lumps to be loaded/unloaded into memory.
+
+static void WI_loadUnloadData(load_callback_t callback)
+{
+ int i, j;
+ char name[9];
+ anim_t *a;
+
+ if (gamemode == commercial)
+ {
+ for (i=0 ; i<NUMCMAPS ; i++)
+ {
+ DEH_snprintf(name, 9, "CWILV%2.2d", i);
+ callback(name, &lnames[i]);
+ }
+ }
+ else
+ {
+ for (i=0 ; i<NUMMAPS ; i++)
+ {
+ DEH_snprintf(name, 9, "WILV%d%d", wbs->epsd, i);
+ callback(name, &lnames[i]);
+ }
+
+ // you are here
+ callback(DEH_String("WIURH0"), &yah[0]);
+
+ // you are here (alt.)
+ callback(DEH_String("WIURH1"), &yah[1]);
+
+ // splat
+ callback(DEH_String("WISPLAT"), &splat[0]);
+
+ 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
+ DEH_snprintf(name, 9, "WIA%d%.2d%.2d", wbs->epsd, j, i);
+ callback(name, &a->p[i]);
+ }
+ else
+ {
+ // HACK ALERT!
+ a->p[i] = anims[1][4].p[i];
+ }
+ }
+ }
+ }
+ }
+
+ // More hacks on minus sign.
+ callback(DEH_String("WIMINUS"), &wiminus);
+
+ for (i=0;i<10;i++)
+ {
+ // numbers 0-9
+ DEH_snprintf(name, 9, "WINUM%d", i);
+ callback(name, &num[i]);
+ }
+
+ // percent sign
+ callback(DEH_String("WIPCNT"), &percent);
+
+ // "finished"
+ callback(DEH_String("WIF"), &finished);
+
+ // "entering"
+ callback(DEH_String("WIENTER"), &entering);
+
+ // "kills"
+ callback(DEH_String("WIOSTK"), &kills);
+
+ // "scrt"
+ callback(DEH_String("WIOSTS"), &secret);
+
+ // "secret"
+ callback(DEH_String("WISCRT2"), &sp_secret);
+
+ // french wad uses WIOBJ (?)
+ if (W_CheckNumForName(DEH_String("WIOBJ")) >= 0)
+ {
+ // "items"
+ if (netgame && !deathmatch)
+ callback(DEH_String("WIOBJ"), &items);
+ else
+ callback(DEH_String("WIOSTI"), &items);
+ } else {
+ callback(DEH_String("WIOSTI"), &items);
+ }
+
+ // "frgs"
+ callback(DEH_String("WIFRGS"), &frags);
+
+ // ":"
+ callback(DEH_String("WICOLON"), &colon);
+
+ // "time"
+ callback(DEH_String("WITIME"), &timepatch);
+
+ // "sucks"
+ callback(DEH_String("WISUCKS"), &sucks);
+
+ // "par"
+ callback(DEH_String("WIPAR"), &par);
+
+ // "killers" (vertical)
+ callback(DEH_String("WIKILRS"), &killers);
+
+ // "victims" (horiz)
+ callback(DEH_String("WIVCTMS"), &victims);
+
+ // "total"
+ callback(DEH_String("WIMSTT"), &total);
+
+ for (i=0 ; i<MAXPLAYERS ; i++)
+ {
+ // "1,2,3,4"
+ DEH_snprintf(name, 9, "STPB%d", i);
+ callback(name, &p[i]);
+
+ // "1,2,3,4"
+ DEH_snprintf(name, 9, "WIBP%d", i+1);
+ callback(name, &bp[i]);
+ }
+
+ // Background image
+
+ if (gamemode == commercial)
+ {
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
+ }
+ else if (gamemode == retail && wbs->epsd == 3)
+ {
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
+ }
+ else
+ {
+ DEH_snprintf(name, 9, "WIMAP%d", wbs->epsd);
+ }
+
+ // Draw backdrop and save to a temporary buffer
+
+ callback(name, &background);
+}
+
+static void WI_loadCallback(char *name, patch_t **variable)
+{
+ *variable = W_CacheLumpName(name, PU_STATIC);
+}
+
+void WI_loadData(void)
+{
+ if (gamemode == commercial)
+ {
+ NUMCMAPS = 32;
+ lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS,
+ PU_STATIC, NULL);
+ }
+ else
+ {
+ lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMMAPS,
+ PU_STATIC, NULL);
+ }
+
+ WI_loadUnloadData(WI_loadCallback);
+
+ // These two graphics are special cased because we're sharing
+ // them with the status bar code
+
+ // your face
+ star = W_CacheLumpName(DEH_String("STFST01"), PU_STATIC);
+
+ // dead face
+ bstar = W_CacheLumpName(DEH_String("STFDEAD0"), PU_STATIC);
+}
+
+static void WI_unloadCallback(char *name, patch_t **variable)
+{
+ W_ReleaseLumpName(name);
+ *variable = NULL;
+}
+
+void WI_unloadData(void)
+{
+ WI_loadUnloadData(WI_unloadCallback);
+
+ // We do not free these lumps as they are shared with the status
+ // bar code.
+
+ // W_ReleaseLumpName("STFST01");
+ // W_ReleaseLumpName("STFDEAD0");
+}
+
+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;
+ }
+}
+
+
+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;
+
+ if (!wbs->maxitems)
+ wbs->maxitems = 1;
+
+ if (!wbs->maxsecret)
+ wbs->maxsecret = 1;
+
+ if ( gamemode != retail )
+ if (wbs->epsd > 2)
+ wbs->epsd -= 3;
+}
+
+void WI_Start(wbstartstruct_t* wbstartstruct)
+{
+ WI_initVariables(wbstartstruct);
+ WI_loadData();
+
+ if (deathmatch)
+ WI_initDeathmatchStats();
+ else if (netgame)
+ WI_initNetgameStats();
+ else
+ WI_initStats();
+}
+#endif
diff --git a/src/strife/wi_stuff.h b/src/strife/wi_stuff.h
new file mode 100644
index 00000000..3ddd4950
--- /dev/null
+++ b/src/strife/wi_stuff.h
@@ -0,0 +1,59 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __WI_STUFF__
+#define __WI_STUFF__
+
+// haleyjd 08/23/2010: Strife does not have an intermission
+#if 0
+//#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);
+
+// Shut down the intermission screen
+void WI_End(void);
+
+#endif
+#endif