diff options
Diffstat (limited to 'src')
125 files changed, 66816 insertions, 14 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 6c0adfae..0b747f89 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,11 +1,12 @@ -SUBDIRS=doom heretic hexen setup +SUBDIRS=doom heretic hexen strife setup gamesdir = $(prefix)/games games_PROGRAMS = @PROGRAM_PREFIX@doom \ @PROGRAM_PREFIX@heretic \ @PROGRAM_PREFIX@hexen \ + @PROGRAM_PREFIX@strife \ @PROGRAM_PREFIX@server \ @PROGRAM_PREFIX@setup @@ -167,6 +168,14 @@ endif @PROGRAM_PREFIX@hexen_LDADD = hexen/libhexen.a $(EXTRA_LIBS) +if HAVE_WINDRES +@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc +else +@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) +endif + +@PROGRAM_PREFIX@strife_LDADD = strife/libstrife.a $(EXTRA_LIBS) + # Source files needed for chocolate-setup: SETUP_FILES= \ diff --git a/src/d_event.h b/src/d_event.h index e47f82df..25334a96 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -89,6 +89,27 @@ typedef enum } buttoncode_t; +// villsa [STRIFE] Strife specific buttons +// TODO - not finished +typedef enum +{ + // Player view look up + BT2_LOOKUP = 1, + // Player view look down + BT2_LOOKDOWN = 2, + // Center player's view + BT2_CENTERVIEW = 4, + // Use inventory item + BT2_INVUSE = 8, + // Drop inventory item + BT2_INVDROP = 16, + // Jump up and down + BT2_JUMP = 32, + // Use medkit + BT2_HEALTH = 128, + +} buttoncode2_t; + diff --git a/src/d_iwad.c b/src/d_iwad.c index 72e3e3ad..a6187c10 100644 --- a/src/d_iwad.c +++ b/src/d_iwad.c @@ -51,6 +51,8 @@ static iwad_t iwads[] = { "heretic.wad", heretic, retail, "Heretic" }, { "heretic1.wad", heretic, shareware, "Heretic Shareware" }, { "hexen.wad", hexen, commercial, "Hexen" }, + //{ "strife0.wad", strife, commercial, "Strife" }, // haleyjd: STRIFE-FIXME + { "strife1.wad", strife, commercial, "Strife" }, }; // Array of locations to search for IWAD files diff --git a/src/d_iwad.h b/src/d_iwad.h index f95b4258..d92dbeff 100644 --- a/src/d_iwad.h +++ b/src/d_iwad.h @@ -35,6 +35,7 @@ | (1 << pack_plut)) #define IWAD_MASK_HERETIC (1 << heretic) #define IWAD_MASK_HEXEN (1 << hexen) +#define IWAD_MASK_STRIFE (1 << strife) typedef struct { diff --git a/src/d_mode.c b/src/d_mode.c index 453ae4eb..4832e01b 100644 --- a/src/d_mode.c +++ b/src/d_mode.c @@ -48,6 +48,7 @@ static struct { heretic, registered, 3, 9 }, { heretic, retail, 5, 9 }, { hexen, commercial, 1, 40 }, + { strife, commercial, 1, 34 }, }; // Check that a gamemode+gamemission received over the network is valid. @@ -131,6 +132,7 @@ static struct { { doom, exe_final }, { heretic, exe_heretic_1_3 }, { hexen, exe_hexen_1_1 }, + { strife, exe_strife_1_31 }, }; boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version) @@ -171,6 +173,7 @@ boolean D_IsEpisodeMap(GameMission_t mission) case doom2: case pack_tnt: case pack_plut: + case strife: default: return false; } diff --git a/src/d_mode.h b/src/d_mode.h index 29f61c10..20cb89e2 100644 --- a/src/d_mode.h +++ b/src/d_mode.h @@ -40,6 +40,7 @@ typedef enum pack_plut, // Final Doom: The Plutonia Experiment heretic, // Heretic hexen, // Hexen + strife, // Strife none } GameMission_t; @@ -69,7 +70,8 @@ typedef enum exe_heretic_1_3, // Heretic 1.3 - exe_hexen_1_1 // Hexen 1.1 + exe_hexen_1_1, // Hexen 1.1 + exe_strife_1_31, // Strife v1.31 } GameVersion_t; // Skill level. diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index b3651835..cb6156ad 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -44,7 +44,14 @@ typedef struct short angleturn; // <<16 for angle delta byte chatchar; byte buttons; + // villsa [STRIFE] according to the asm, + // consistancy is a short, not a byte byte consistancy; // checks for net game + + // villsa - Strife specific: + + byte buttons2; + int inventory; // Heretic/Hexen specific: diff --git a/src/doomfeatures.h b/src/doomfeatures.h index 46e26e52..1c994b70 100644 --- a/src/doomfeatures.h +++ b/src/doomfeatures.h @@ -36,8 +36,9 @@ #define FEATURE_DEHACKED 1 // Enables multiplayer support (network games) +// STRIFE-TODO: multiplayer is currently broken ... -#define FEATURE_MULTIPLAYER 1 +// #define FEATURE_MULTIPLAYER 1 // Enables sound output diff --git a/src/i_video.c b/src/i_video.c index 9d70e88e..6bf2f179 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -1888,6 +1888,8 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) #ifndef __MACOSX__ flags |= SDL_RESIZABLE; #endif + // villsa - center window + SDL_putenv("SDL_VIDEO_CENTERED=1"); } screen = SDL_SetVideoMode(w, h, screen_bpp, flags); diff --git a/src/m_config.c b/src/m_config.c index a0f97dc2..bda9828c 100644 --- a/src/m_config.c +++ b/src/m_config.c @@ -142,6 +142,12 @@ static default_t doom_defaults_list[] = CONFIG_VARIABLE_INT(music_volume), //! + // Volume of voice sound effects, range 0-15. Strife only. + // + + CONFIG_VARIABLE_INT(voice_volume), + + //! // If non-zero, messages are displayed on the heads-up display // in the game ("picked up a clip", etc). If zero, these messages // are not displayed. @@ -186,6 +192,12 @@ static default_t doom_defaults_list[] = CONFIG_VARIABLE_KEY(key_straferight), //! + // Keyboard key to use health. (Strife only) + // + + CONFIG_VARIABLE_KEY(key_useHealth), + + //! // Keyboard key to jump. // @@ -228,6 +240,42 @@ static default_t doom_defaults_list[] = CONFIG_VARIABLE_KEY(key_lookcenter), //! + // Keyboard key to query inventory. (Strife only) + // + + CONFIG_VARIABLE_KEY(key_invquery), + + //! + // Keyboard key to display mission objective. (Strife only) + // + + CONFIG_VARIABLE_KEY(key_mission), + + //! + // Keyboard key to display inventory popup. (Strife only) + // + + CONFIG_VARIABLE_KEY(key_invPop), + + //! + // Keyboard key to display keys popup. (Strife only) + // + + CONFIG_VARIABLE_KEY(key_invKey), + + //! + // Keyboard key to jump to start of inventory. (Strife only) + // + + CONFIG_VARIABLE_KEY(key_invHome), + + //! + // Keyboard key to jump to end of inventory. (Strife only) + // + + CONFIG_VARIABLE_KEY(key_invEnd), + + //! // Keyboard key to scroll left in the inventory. // @@ -240,12 +288,48 @@ static default_t doom_defaults_list[] = CONFIG_VARIABLE_KEY(key_invright), //! + // Keyboard key to scroll left in the inventory. (Strife) + // + + CONFIG_VARIABLE_KEY(key_invLeft), + + //! + // Keyboard key to scroll right in the inventory. (Strife) + // + + CONFIG_VARIABLE_KEY(key_invRight), + + //! // Keyboard key to use the current item in the inventory. // CONFIG_VARIABLE_KEY(key_useartifact), //! + // Keyboard key to use inventory item. (Strife) + // + + CONFIG_VARIABLE_KEY(key_invUse), + + //! + // Keyboard key to drop an inventory item. (Strife only) + // + + CONFIG_VARIABLE_KEY(key_invDrop), + + //! + // Keyboard key to look up. (Strife) + // + + CONFIG_VARIABLE_KEY(key_lookUp), + + //! + // Keyboard key to look down. (Strife) + // + + CONFIG_VARIABLE_KEY(key_lookDown), + + //! // Keyboard key to fire the currently selected weapon. // @@ -425,6 +509,12 @@ static default_t doom_defaults_list[] = CONFIG_VARIABLE_INT(messageson), + //! + // Name of background flat used by view border. (Strife only) + // + + CONFIG_VARIABLE_STRING(back_flat), + //! // Multiplayer chat macro: message to send when alt+0 is pressed. diff --git a/src/m_controls.c b/src/m_controls.c index 60a96ac2..409f26bf 100644 --- a/src/m_controls.c +++ b/src/m_controls.c @@ -68,6 +68,26 @@ int key_useartifact = KEY_ENTER; int key_jump = '/'; // +// Strife key controls +// +// haleyjd 09/01/10 +// + +// Note: Strife also uses key_invleft, key_invright, key_jump, key_lookup, and +// key_lookdown, but with different default values. + +int key_usehealth = 'h'; +int key_invquery = 'q'; +int key_mission = 'w'; +int key_invpop = 'z'; +int key_invkey = 'k'; +int key_invhome = KEY_HOME; +int key_invend = KEY_END; +int key_invuse = KEY_ENTER; +int key_invdrop = KEY_BACKSPACE; + + +// // Mouse controls // @@ -234,6 +254,41 @@ void M_BindHexenControls(void) M_BindVariable("joyb_jump", &joybjump); } +void M_BindStrifeControls(void) +{ + // These are shared with all games, but have different defaults: + key_message_refresh = '/'; + + // These keys are shared with Heretic/Hexen but have different defaults: + key_jump = 'a'; + key_lookup = KEY_PGUP; + key_lookdown = KEY_PGDN; + key_invleft = KEY_INS; + key_invright = KEY_DEL; + + M_BindVariable("key_jump", &key_jump); + M_BindVariable("key_lookUp", &key_lookup); + M_BindVariable("key_lookDown", &key_lookdown); + M_BindVariable("key_invLeft", &key_invleft); + M_BindVariable("key_invRight", &key_invright); + + // Custom Strife-only Keys: + M_BindVariable("key_useHealth", &key_usehealth); + M_BindVariable("key_invquery", &key_invquery); + M_BindVariable("key_mission", &key_mission); + M_BindVariable("key_invPop", &key_invpop); + M_BindVariable("key_invKey", &key_invkey); + M_BindVariable("key_invHome", &key_invhome); + M_BindVariable("key_invEnd", &key_invend); + M_BindVariable("key_invUse", &key_invuse); + M_BindVariable("key_invDrop", &key_invdrop); + + // Strife also supports jump on mouse and joystick, and in the exact same + // manner as Hexen! + M_BindVariable("mouseb_jump", &mousebjump); + M_BindVariable("joyb_jump", &joybjump); +} + void M_BindWeaponControls(void) { M_BindVariable("key_weapon1", &key_weapon1); @@ -303,8 +358,8 @@ void M_BindMenuControls(void) void M_BindChatControls(unsigned int num_players) { - char name[20]; - int i; + char name[32]; // haleyjd: 20 not large enough - Thank you, come again! + unsigned int i; // haleyjd: signedness conflict M_BindVariable("key_multi_msg", &key_multi_msg); diff --git a/src/m_controls.h b/src/m_controls.h index 389c94a0..3e50d557 100644 --- a/src/m_controls.h +++ b/src/m_controls.h @@ -49,6 +49,17 @@ extern int key_invleft; extern int key_invright; extern int key_useartifact; +// villsa [STRIFE] strife keys +extern int key_usehealth; +extern int key_invquery; +extern int key_mission; +extern int key_invpop; +extern int key_invkey; +extern int key_invhome; +extern int key_invend; +extern int key_invuse; +extern int key_invdrop; + extern int key_message_refresh; extern int key_pause; @@ -154,6 +165,7 @@ extern int dclick_use; void M_BindBaseControls(void); void M_BindHereticControls(void); void M_BindHexenControls(void); +void M_BindStrifeControls(void); void M_BindWeaponControls(void); void M_BindMapControls(void); void M_BindMenuControls(void); diff --git a/src/midifile.c b/src/midifile.c index 1990dcdc..e9af051c 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -36,6 +36,11 @@ #define TRACK_CHUNK_ID "MTrk" #define MAX_BUFFER_SIZE 0x10000 +// haleyjd 09/09/10: packing required +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif + typedef struct { byte chunk_id[4]; @@ -50,6 +55,11 @@ typedef struct unsigned short time_division; } PACKEDATTR midi_header_t; +// haleyjd 09/09/10: packing off. +#ifdef _MSC_VER +#pragma pack(pop) +#endif + typedef struct { // Length in bytes: diff --git a/src/setup/keyboard.c b/src/setup/keyboard.c index 3d9f9977..7ee523bb 100644 --- a/src/setup/keyboard.c +++ b/src/setup/keyboard.c @@ -39,11 +39,13 @@ static int always_run = 0; static int *controls[] = { &key_left, &key_right, &key_up, &key_down, &key_strafeleft, &key_straferight, &key_fire, - &key_use, &key_strafe, &key_speed, &key_jump, + &key_use, &key_strafe, &key_speed, &key_jump, &key_flyup, &key_flydown, &key_flycenter, &key_lookup, &key_lookdown, &key_lookcenter, - &key_invleft, &key_invright, &key_useartifact, - &key_pause, + &key_invleft, &key_invright, &key_invquery, + &key_invuse, &key_invpop, &key_invkey, + &key_invhome, &key_invend, &key_invdrop, + &key_useartifact, &key_pause, &key_usehealth, &key_weapon1, &key_weapon2, &key_weapon3, &key_weapon4, &key_weapon5, &key_weapon6, &key_weapon7, &key_weapon8, @@ -174,7 +176,9 @@ static void ConfigExtraKeys(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) txt_window_t *window; txt_scrollpane_t *scrollpane; txt_table_t *table; - boolean extra_keys = gamemission == heretic || gamemission == hexen; + boolean extra_keys = gamemission == heretic + || gamemission == hexen + || gamemission == strife; window = TXT_NewWindow("Extra keyboard controls"); @@ -205,7 +209,23 @@ static void ConfigExtraKeys(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) AddKeyControl(table, "Inventory left", &key_invleft); AddKeyControl(table, "Inventory right", &key_invright); - AddKeyControl(table, "Use artifact", &key_useartifact); + + if (gamemission == strife) + { + AddKeyControl(table, "Home", &key_invhome); + AddKeyControl(table, "End", &key_invend); + AddKeyControl(table, "Query", &key_invquery); + AddKeyControl(table, "Drop", &key_invdrop); + AddKeyControl(table, "PopWeap", &key_invpop); + AddKeyControl(table, "PopMiss", &key_mission); + AddKeyControl(table, "PopKey", &key_invkey); + AddKeyControl(table, "Use", &key_invuse); + AddKeyControl(table, "Use health", &key_usehealth); + } + else + { + AddKeyControl(table, "Use artifact", &key_useartifact); + } } else { diff --git a/src/setup/mode.c b/src/setup/mode.c index 702db67d..3852db25 100644 --- a/src/setup/mode.c +++ b/src/setup/mode.c @@ -91,6 +91,15 @@ static mission_config_t mission_configs[] = "hexen.cfg", PROGRAM_PREFIX "hexen.cfg", PROGRAM_PREFIX "hexen" + }, + { + "Strife", + strife, + IWAD_MASK_STRIFE, + "strife", + "strife.cfg", + PROGRAM_PREFIX "strife.cfg", + PROGRAM_PREFIX "strife" } }; @@ -103,6 +112,7 @@ static int screenblocks = 9; static int detailLevel = 0; static char *savedir = NULL; static char *executable = NULL; +static char *back_flat = "F_PAVE01"; static void BindMiscVariables(void) { @@ -119,6 +129,11 @@ static void BindMiscVariables(void) M_BindVariable("savedir", &savedir); M_BindVariable("messageson", &showMessages); } + + if (gamemission == strife) + { + M_BindVariable("back_flat", &back_flat); + } } // @@ -146,6 +161,11 @@ void InitBindings(void) M_BindHexenControls(); } + if (gamemission == strife) + { + M_BindStrifeControls(); + } + // All other variables BindCompatibilityVariables(); diff --git a/src/setup/sound.c b/src/setup/sound.c index 627549b5..d8dc129e 100644 --- a/src/setup/sound.c +++ b/src/setup/sound.c @@ -74,6 +74,7 @@ int opl_io_port = 0x388; static int numChannels = 8; static int sfxVolume = 15; static int musicVolume = 15; +static int voiceVolume = 15; static int use_libsamplerate = 0; // DOS specific variables: these are unused but should be maintained @@ -212,6 +213,14 @@ void ConfigSound(void) TXT_NewSpinControl(&sfxVolume, 0, 15), NULL); + if (gamemission == strife) + { + TXT_AddWidgets(sfx_table, + TXT_NewLabel("Voice volume"), + TXT_NewSpinControl(&voiceVolume, 0, 15), + NULL); + } + TXT_SetColumnWidths(music_table, 20, 14); TXT_AddWidgets(music_table, @@ -238,9 +247,14 @@ void BindSoundVariables(void) M_BindVariable("use_libsamplerate", &use_libsamplerate); M_BindVariable("snd_sbport", &snd_sbport); - M_BindVariable("snd_sbirq", &snd_sbirq); - M_BindVariable("snd_sbdma", &snd_sbdma); - M_BindVariable("snd_mport", &snd_mport); + M_BindVariable("snd_sbirq", &snd_sbirq); + M_BindVariable("snd_sbdma", &snd_sbdma); + M_BindVariable("snd_mport", &snd_mport); + + if (gamemission == strife) + { + M_BindVariable("voice_volume", &voiceVolume); + } // Before SDL_mixer version 1.2.11, MIDI music caused the game // to crash when it looped. If this is an old SDL_mixer version, 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..4dc0cabd --- /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 d_net.h \ + 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..48c6b475 --- /dev/null +++ b/src/strife/am_map.c @@ -0,0 +1,1400 @@ +// 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 0 +#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; + +extern boolean viewactive; + +void +V_MarkRect +( int x, + int y, + int width, + int height ); + +// 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, 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 cheatstate=0; + 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 + { + cheatstate=0; + 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..52a9e23c --- /dev/null +++ b/src/strife/d_englsh.h @@ -0,0 +1,599 @@ +// 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" + +#define HUSTR_CHATMACRO1 "I'm ready to kick butt!" +#define HUSTR_CHATMACRO2 "I'm OK." +#define HUSTR_CHATMACRO3 "I'm not looking too good!" +#define HUSTR_CHATMACRO4 "Help!" +#define HUSTR_CHATMACRO5 "You suck!" +#define HUSTR_CHATMACRO6 "Next time, scumbag..." +#define HUSTR_CHATMACRO7 "Come here!" +#define HUSTR_CHATMACRO8 "I'll take care of it." +#define HUSTR_CHATMACRO9 "Yes" +#define HUSTR_CHATMACRO0 "No" + +#define HUSTR_TALKTOSELF1 "You mumble to yourself" +#define HUSTR_TALKTOSELF2 "Who's there?" +#define HUSTR_TALKTOSELF3 "You scare yourself" +#define HUSTR_TALKTOSELF4 "You start to rave" +#define HUSTR_TALKTOSELF5 "You've lost it..." + +#define HUSTR_MESSAGESENT "[Message Sent]" + +// The following should NOT be changed unless it seems +// just AWFULLY necessary + +#define HUSTR_PLRGREEN "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 (no keys) Added" + +#define STSTR_NCON "No Clipping Mode ON" +#define STSTR_NCOFF "No Clipping Mode OFF" + +#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp" +#define STSTR_BEHOLDX "Power-up Toggled" + +#define STSTR_CHOPPERS "... doesn't suck - GM" +#define STSTR_CLEV "Changing Level..." + +// +// 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..8a8547bf --- /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] TODO - set ammo +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..95b1b643 --- /dev/null +++ b/src/strife/d_main.c @@ -0,0 +1,1997 @@ +// 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 "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" + +// +// 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 showintro = true; // [STRIFE] checkparm of -nograph, disables intro +boolean singletics = false; // debug flag to cancel adaptiveness + + +//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; + + +void D_CheckNetGame (void); +void D_ProcessEvents (void); +void G_BuildTiccmd (ticcmd_t* cmd); +void D_DoAdvanceDemo (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; +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]); + + if (gamestate == GS_LEVEL && gametic) + { + HU_Drawer (); + if(ST_DrawExternal()) + popupactivestate = true; + else if(popupactivestate) + { + popupactivestate = false; + menuactivestate = 1; + } + } + + // 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 + + G_DrawMouseSpeedBox(); + } + + menuactivestate = menuactive; + viewactivestate = viewactive; + inhelpscreensstate = inhelpscreens; + oldgamestate = wipegamestate = gamestate; + + // 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 + M_BindVariable("mouse_sensitivity", &mouseSensitivity); + M_BindVariable("sfx_volume", &sfxVolume); + M_BindVariable("music_volume", &musicVolume); + M_BindVariable("voice_volume", &voiceVolume); + M_BindVariable("show_messages", &showMessages); + M_BindVariable("screenblocks", &screenblocks); + M_BindVariable("detaillevel", &detailLevel); + 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); + + // 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. +// +extern boolean demorecording; + +void D_DoomLoop (void) +{ + if (demorecording) + G_BeginRecording (); + + TryRunTics(); + + if(!showintro) // [STRIFE] + { + 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 + if (singletics) + { + I_StartTic (); + D_ProcessEvents (); + G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]); + if (advancedemo) + D_DoAdvanceDemo (); + M_Ticker (); + G_Ticker (); + gametic++; + maketic++; + } + else + { + 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.31" + " " +}; + +// +// 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"); +} + +static void SetSaveGameDir(char *iwad_filename) +{ + char *sep; + char *basefile; + + // Extract the base filename + + sep = strrchr(iwad_filename, DIR_SEPARATOR); + + if (sep == NULL) + { + basefile = iwad_filename; + } + else + { + basefile = sep + 1; + } + + // ~/.chocolate-doom/savegames/ + + savegamedir = Z_Malloc(strlen(configdir) + 30, PU_STATIC, 0); + sprintf(savegamedir, "%ssavegames%c", configdir, + DIR_SEPARATOR); + + M_MakeDirectory(savegamedir); + + // eg. ~/.chocolate-doom/savegames/doom2.wad/ + + sprintf(savegamedir + strlen(savegamedir), "%s%c", + basefile, DIR_SEPARATOR); + + M_MakeDirectory(savegamedir); + + // haleyjd 20110210: Create Strife hub save folders + M_CreateSaveDirs(savegamedir); +} + +// Check if the IWAD file is the Chex Quest IWAD. +// Returns true if this is chex.wad. +// haleyjd 08/23/10: there is no Chex Quest based on Strife, +// though I must admit that makes an intriguing idea.... +/* +static boolean CheckChex(char *iwadname) +{ + char *chex_iwadname = "chex.wad"; + + return (strlen(iwadname) > strlen(chex_iwadname) + && !strcasecmp(iwadname + strlen(iwadname) - strlen(chex_iwadname), + chex_iwadname)); +} +*/ + +// 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[] = { + {"Doom 1.9", "1.9", exe_doom_1_9}, + {"Ultimate Doom", "ultimate", exe_ultimate}, + {"Final Doom", "final", exe_final}, + {"Chex Quest", "chex", exe_chex}, + { NULL, NULL, 0}, +}; + +// Initialize the game version + +static void InitGameVersion(void) +{ + int p; + int i; + + //! + // @arg <version> + // @category compat + // + // Emulate a specific version of Doom. Valid values are "1.9", + // "ultimate" and "final". + // + + 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 + { + // Determine automatically + + // haleyjd 08/23/10: Removed Chex mode, as it is irrelevant to Strife + if (gamemode == shareware || gamemode == registered) + { + // original + + gameversion = exe_doom_1_9; + } + else if (gamemode == retail) + { + gameversion = exe_ultimate; + } + else if (gamemode == commercial) + { + if (gamemission == doom2) + { + gameversion = exe_doom_1_9; + } + else + { + // Final Doom: tnt or plutonia + + gameversion = exe_final; + } + } + } + + // The original exe does not support retail - 4th episode not supported + + if (gameversion < exe_ultimate && gamemode == retail) + { + gamemode = registered; + } + + // EXEs prior to the Final Doom exes do not support Final Doom. + + if (gameversion < exe_final && gamemode == commercial) + { + gamemission = doom2; + } +} + +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; + } + } +} + +// Load the Chex Quest dehacked file, if we are in Chex mode. +// haleyjd 08/23/2010: Removed, as irrelevant to Strife. +/* +static void LoadChexDeh(void) +{ + char *chex_deh; + + if (gameversion == exe_chex) + { + chex_deh = D_FindWADByName("chex.deh"); + + if (chex_deh == NULL) + { + I_Error("Unable to find Chex Quest dehacked file (chex.deh).\n" + "The dehacked file is required in order to emulate\n" + "chex.exe correctly. It can be found in your nearest\n" + "/idgames repository mirror at:\n\n" + " utils/exe_edit/patches/chexdeh.zip"); + } + + if (!DEH_LoadFile(chex_deh)) + { + I_Error("Failed to load chex.deh needed for emulating chex.exe."); + } + } +} +*/ + +// 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 || M_CheckParm("-testcontrols") > 0) + { + 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 void D_InitIntroSequence(void) +{ + if(showintro) + { + // 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... + 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...")); + } + */ +} + +// +// 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) +{ + if(devparm) + return; + + ++introprogress; + if(introprogress >= MAXINTROPROGRESS) + { + D_IntroBackground(); // haleyjd: clear the bg anyway + S_StartSound(NULL, sfx_psdtha); + } + 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); + + M_FindResponseFile (); + + // haleyjd 20110206 [STRIFE]: -nograph parameter + + //! + // @vanilla + // + // Disable graphical introduction sequence + // + + if (M_CheckParm("-nograph") > 0) + 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")) + { + printf("\nSearching for servers on Internet ...\n"); + p = NET_MasterQuery(NET_QueryPrintCallback, NULL); + printf("\n%i server(s) found.\n", p); + 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")) + { + printf("\nSearching for servers on local LAN ...\n"); + p = NET_LANQuery(NET_QueryPrintCallback, NULL); + printf("\n%i server(s) found.\n", p); + 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"); + + //! + // @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; + + //! + // @category net + // @vanilla + // + // Start a deathmatch game. + // + + if (M_CheckParm ("-deathmatch")) + deathmatch = 1; + + //! + // @category net + // @vanilla + // + // Start a deathmatch 2.0 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(); + + // 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(); + //LoadChexDeh(); - haleyjd: removed, as irrelevant to Strife + D_SetGameDescription(); + SetSaveGameDir(iwadfile); + + // haleyjd 20110206 [STRIFE] Startup the introduction sequence + D_InitIntroSequence(); + D_IntroTick(); + + // 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; + } + + // Undocumented: + // Invoked by setup to test the controls. + + p = M_CheckParm("-testcontrols"); + + if (p > 0) + { + startepisode = 1; + startmap = 1; + autostart = true; + testcontrols = 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] + + if(devparm) // [STRIFE] + DEH_printf("S_Init: Setting up sound.\n"); + S_Init (sfxVolume * 8, musicVolume * 8, voiceVolume * 8); // [STRIFE]: voice + D_IntroTick(); // [STRIFE] + + 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(); + + // 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..7e1644e8 --- /dev/null +++ b/src/strife/d_net.c @@ -0,0 +1,635 @@ +// 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 "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 "deh_main.h" + +#include "net_client.h" +#include "net_gui.h" +#include "net_io.h" +#include "net_query.h" +#include "net_server.h" +#include "net_sdl.h" +#include "net_loop.h" + +// +// NETWORKING +// +// gametic is the tic about to (or currently being) run +// maketic is the tick that hasn't had control made for it yet +// nettics[] has the maketics for all players +// +// a gametic cannot be run until nettics[] > gametic for all players +// + +ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; +int nettics[MAXPLAYERS]; + +int maketic; + +// Used for original sync code. + +int lastnettic; +int skiptics = 0; + +// Reduce the bandwidth needed by sampling game input less and transmitting +// less. If ticdup is 2, sample half normal, 3 = one third normal, etc. + +int ticdup; + +// Send this many extra (backup) tics in each packet. + +int extratics; + +// Amount to offset the timer for game sync. + +fixed_t offsetms; + +// Use new client syncronisation code + +boolean net_cl_new_sync = true; + +// Connected but not participating in the game (observer) + +boolean drone = false; + +// 35 fps clock adjusted by offsetms milliseconds + +static int GetAdjustedTime(void) +{ + int time_ms; + + time_ms = I_GetTimeMS(); + + if (net_cl_new_sync) + { + // Use the adjustments from net_client.c only if we are + // using the new sync mode. + + time_ms += (offsetms / FRACUNIT); + } + + return (time_ms * TICRATE) / 1000; +} + +// +// NetUpdate +// Builds ticcmds for console player, +// sends out a packet +// +int lasttime; + +void NetUpdate (void) +{ + int nowtime; + int newtics; + int i; + int gameticdiv; + + // If we are running with singletics (timing a demo), this + // is all done separately. + + if (singletics) + return; + +#ifdef FEATURE_MULTIPLAYER + + // Run network subsystems + + NET_CL_Run(); + NET_SV_Run(); + +#endif + + // check time + nowtime = GetAdjustedTime() / ticdup; + newtics = nowtime - lasttime; + + lasttime = nowtime; + + if (skiptics <= newtics) + { + newtics -= skiptics; + skiptics = 0; + } + else + { + skiptics -= newtics; + newtics = 0; + } + + // build new ticcmds for console player + gameticdiv = gametic/ticdup; + + for (i=0 ; i<newtics ; i++) + { + ticcmd_t cmd; + + I_StartTic (); + D_ProcessEvents (); + + // Always run the menu + + M_Ticker (); + + if (drone) + { + // In drone mode, do not generate any ticcmds. + + continue; + } + + if (net_cl_new_sync) + { + // If playing single player, do not allow tics to buffer + // up very far + + if ((!netgame || demoplayback) && maketic - gameticdiv > 2) + break; + + // Never go more than ~200ms ahead + + if (maketic - gameticdiv > 8) + break; + } + else + { + if (maketic - gameticdiv >= 5) + break; + } + + //printf ("mk:%i ",maketic); + G_BuildTiccmd(&cmd); + +#ifdef FEATURE_MULTIPLAYER + + if (netgame && !demoplayback) + { + NET_CL_SendTiccmd(&cmd, maketic); + } + +#endif + netcmds[consoleplayer][maketic % BACKUPTICS] = cmd; + + ++maketic; + nettics[consoleplayer] = maketic; + } +} + +// +// Start game loop +// +// Called after the screen is set but before the game starts running. +// + +void D_StartGameLoop(void) +{ + lasttime = GetAdjustedTime() / ticdup; +} + + +// +// D_CheckNetGame +// Works out player numbers among the net participants +// +extern int viewangleoffset; + +void D_CheckNetGame (void) +{ + int i; + int num_players; + + // Call D_QuitNetGame on exit + + I_AtExit(D_QuitNetGame, true); + + // default values for single player + + consoleplayer = 0; + netgame = false; + ticdup = 1; + extratics = 1; + lowres_turn = false; + offsetms = 0; + + for (i=0; i<MAXPLAYERS; i++) + { + playeringame[i] = false; + nettics[i] = 0; + } + + playeringame[0] = true; + +#ifdef FEATURE_MULTIPLAYER + + { + net_addr_t *addr = NULL; + + //! + // @category net + // + // Start a multiplayer server, listening for connections. + // + + if (M_CheckParm("-server") > 0) + { + NET_SV_Init(); + NET_SV_AddModule(&net_loop_server_module); + NET_SV_AddModule(&net_sdl_module); + + net_loop_client_module.InitClient(); + addr = net_loop_client_module.ResolveAddress(NULL); + } + else + { + //! + // @category net + // + // Automatically search the local LAN for a multiplayer + // server and join it. + // + + i = M_CheckParm("-autojoin"); + + if (i > 0) + { + addr = NET_FindLANServer(); + NET_SV_RegisterWithMaster(); + + if (addr == NULL) + { + I_Error("No server found on local LAN"); + } + } + + //! + // @arg <address> + // @category net + // + // Connect to a multiplayer server running on the given + // address. + // + + i = M_CheckParmWithArgs("-connect", 1); + + if (i > 0) + { + net_sdl_module.InitClient(); + addr = net_sdl_module.ResolveAddress(myargv[i+1]); + + if (addr == NULL) + { + I_Error("Unable to resolve '%s'\n", myargv[i+1]); + } + } + } + + if (addr != NULL) + { + if (M_CheckParm("-drone") > 0) + { + drone = true; + } + + //! + // @category net + // + // Run as the left screen in three screen mode. + // + + if (M_CheckParm("-left") > 0) + { + viewangleoffset = ANG90; + drone = true; + } + + //! + // @category net + // + // Run as the right screen in three screen mode. + // + + if (M_CheckParm("-right") > 0) + { + viewangleoffset = ANG270; + drone = true; + } + + if (!NET_CL_Connect(addr)) + { + I_Error("D_CheckNetGame: Failed to connect to %s\n", + NET_AddrToString(addr)); + } + + printf("D_CheckNetGame: Connected to %s\n", NET_AddrToString(addr)); + + NET_WaitForStart(); + } + } + +#endif + + num_players = 0; + + for (i=0; i<MAXPLAYERS; ++i) + { + if (playeringame[i]) + ++num_players; + } + + DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", + startskill, deathmatch, startmap, startepisode); + + DEH_printf("player %i of %i (%i nodes)\n", + consoleplayer+1, num_players, 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"); + } + } +} + + +// +// D_QuitNetGame +// Called before quitting to leave a net game +// without hanging the other players +// +void D_QuitNetGame (void) +{ +#ifdef FEATURE_MULTIPLAYER + + NET_SV_Shutdown(); + NET_CL_Disconnect(); + +#endif + +} + +// Returns true if there are currently any players in the game. + +static boolean PlayersInGame(void) +{ + int i; + + for (i=0; i<MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + return true; + } + } + + return false; +} + +static int GetLowTic(void) +{ + int lowtic; + +#ifdef FEATURE_MULTIPLAYER + if (net_client_connected) + { + int i; + + lowtic = INT_MAX; + + for (i=0; i<MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + if (nettics[i] < lowtic) + lowtic = nettics[i]; + } + } + } + else +#endif + { + lowtic = maketic; + } + + return lowtic; +} + +// +// TryRunTics +// +int oldnettics; +int frametics[4]; +int frameon; +int frameskip[4]; +int oldnettics; + +extern boolean advancedemo; + +void TryRunTics (void) +{ + int i; + int lowtic; + int entertic; + static int oldentertics; + int realtics; + int availabletics; + int counts; + + // get real tics + entertic = I_GetTime() / ticdup; + realtics = entertic - oldentertics; + oldentertics = entertic; + + // get available tics + NetUpdate (); + + lowtic = GetLowTic(); + + availabletics = lowtic - gametic/ticdup; + + // decide how many tics to run + + if (net_cl_new_sync) + { + counts = availabletics; + } + else + { + // decide how many tics to run + if (realtics < availabletics-1) + counts = realtics+1; + else if (realtics < availabletics) + counts = realtics; + else + counts = availabletics; + + if (counts < 1) + counts = 1; + + frameon++; + + if (!demoplayback) + { + int keyplayer = -1; + + // ideally maketic should be 1 - 3 tics above lowtic + // if we are consistantly slower, speed up time + + for (i=0 ; i<MAXPLAYERS ; i++) + { + if (playeringame[i]) + { + keyplayer = i; + break; + } + } + + if (keyplayer < 0) + { + // If there are no players, we can never advance anyway + + return; + } + + if (consoleplayer == keyplayer) + { + // the key player does not adapt + } + else + { + if (maketic <= nettics[keyplayer]) + { + lasttime--; + // printf ("-"); + } + + frameskip[frameon & 3] = (oldnettics > nettics[keyplayer]); + oldnettics = maketic; + + if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3]) + { + skiptics = 1; + // printf ("+"); + } + } + } + } + + if (counts < 1) + counts = 1; + + // wait for new tics if needed + + while (!PlayersInGame() || lowtic < gametic/ticdup + counts) + { + NetUpdate (); + + lowtic = GetLowTic(); + + if (lowtic < gametic/ticdup) + I_Error ("TryRunTics: lowtic < gametic"); + + // Don't stay in this loop forever. The menu is still running, + // so return to update the screen + + if (I_GetTime() / ticdup - entertic > 0) + { + return; + } + + I_Sleep(1); + } + + // run the count * ticdup dics + while (counts--) + { + for (i=0 ; i<ticdup ; i++) + { + // check that there are players in the game. if not, we cannot + // run a tic. + + if (!PlayersInGame()) + { + return; + } + + if (gametic/ticdup > lowtic) + I_Error ("gametic>lowtic"); + if (advancedemo) + D_DoAdvanceDemo (); + + G_Ticker (); + gametic++; + + + // modify command for duplicated tics + if (i != ticdup-1) + { + ticcmd_t *cmd; + int buf; + int j; + + buf = (gametic/ticdup)%BACKUPTICS; + for (j=0 ; j<MAXPLAYERS ; j++) + { + cmd = &netcmds[j][buf]; + cmd->chatchar = 0; + if (cmd->buttons & BT_SPECIAL) + cmd->buttons = 0; + } + } + } + NetUpdate (); // check for new console commands + } +} + diff --git a/src/strife/d_net.h b/src/strife/d_net.h new file mode 100644 index 00000000..f801d216 --- /dev/null +++ b/src/strife/d_net.h @@ -0,0 +1,52 @@ +// 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: +// Networking stuff. +// +//----------------------------------------------------------------------------- + + +#ifndef __D_NET__ +#define __D_NET__ + +#include "d_player.h" + +extern int extratics; + +// Create any new ticcmds and broadcast to other players. +void NetUpdate (void); + +// Broadcasts special packets to other players +// to notify of game exit +void D_QuitNetGame (void); + +//? how many ticks to run? +void TryRunTics (void); + +// Called at start of game loop to initialize timers +void D_StartGameLoop(void); + +extern boolean drone; +extern boolean net_cl_new_sync; + +#endif + 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..2c6a9022 --- /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_AmmoMD5Hash(md5_context_t *context) +{ + int i; + + for (i=0; i<NUMAMMO; ++i) + { + MD5_UpdateInt32(context, clipammo[i]); + MD5_UpdateInt32(context, maxammo[i]); + } +} + +deh_section_t deh_section_ammo = +{ + "Ammo", + NULL, + DEH_AmmoStart, + DEH_AmmoParseLine, + NULL, + DEH_AmmoMD5Hash, +}; + diff --git a/src/strife/deh_cheat.c b/src/strife/deh_cheat.c new file mode 100644 index 00000000..c693a2df --- /dev/null +++ b/src/strife/deh_cheat.c @@ -0,0 +1,155 @@ +// 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[] = +{ + {"Change music", &cheat_mus }, + {"Level Warp", &cheat_clev }, + {"Stealth Boots", NULL }, // STRIFE-TODO + {"Sigil piece", NULL }, // STRIFE-TODO + {"FPS", NULL }, // STRIFE-TODO + {"TeleportMapSpot", NULL }, // STRIFE-TODO + {"Gold&StatTokens", NULL }, // STRIFE-TODO + {"God mode", &cheat_god }, + {"Keys", NULL }, // STRIFE-TODO + {"Weapons & Ammo", NULL }, // STRIFE-TODO + {"Massacre", NULL }, // STRIFE-TODO + {"No Clipping", &cheat_noclip }, + {"Berserk", &cheat_powerup[1] }, + {"Invisibility", &cheat_powerup[2] }, + {"Enviro Suit", &cheat_powerup[3] }, + {"Health", NULL }, // STRIFE-TODO + {"Backpack", NULL }, // STRIFE-TODO +}; + +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..9383b94f --- /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_FrameMD5Sum(md5_context_t *context) +{ + int i; + + for (i=0; i<NUMSTATES; ++i) + { + DEH_StructMD5Sum(context, &state_mapping, &states[i]); + } +} + +deh_section_t deh_section_frame = +{ + "Frame", + NULL, + DEH_FrameStart, + DEH_FrameParseLine, + NULL, + DEH_FrameMD5Sum, +}; + diff --git a/src/strife/deh_misc.c b/src/strife/deh_misc.c new file mode 100644 index 00000000..e3f2606c --- /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_MiscMD5Sum(md5_context_t *context) +{ + unsigned int i; + + for (i=0; i<arrlen(misc_settings); ++i) + { + MD5_UpdateInt32(context, *misc_settings[i].value); + } +} + +deh_section_t deh_section_misc = +{ + "Misc", + NULL, + DEH_MiscStart, + DEH_MiscParseLine, + NULL, + DEH_MiscMD5Sum, +}; + 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..d757a178 --- /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_PointerMD5Sum(md5_context_t *context) +{ + int i; + + for (i=0; i<NUMSTATES; ++i) + { + MD5_UpdateInt32(context, CodePointerIndex(&states[i].action)); + } +} + +deh_section_t deh_section_pointer = +{ + "Pointer", + DEH_PointerInit, + DEH_PointerStart, + DEH_PointerParseLine, + NULL, + DEH_PointerMD5Sum, +}; + 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..14b23b0a --- /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_ThingMD5Sum(md5_context_t *context) +{ + int i; + + for (i=0; i<NUMMOBJTYPES; ++i) + { + DEH_StructMD5Sum(context, &thing_mapping, &mobjinfo[i]); + } +} + +deh_section_t deh_section_thing = +{ + "Thing", + NULL, + DEH_ThingStart, + DEH_ThingParseLine, + NULL, + DEH_ThingMD5Sum, +}; + diff --git a/src/strife/deh_weapon.c b/src/strife/deh_weapon.c new file mode 100644 index 00000000..8e89b93e --- /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_WeaponMD5Sum(md5_context_t *context) +{ + int i; + + for (i=0; i<NUMWEAPONS ;++i) + { + DEH_StructMD5Sum(context, &weapon_mapping, &weaponinfo[i]); + } +} + +deh_section_t deh_section_weapon = +{ + "Weapon", + NULL, + DEH_WeaponStart, + DEH_WeaponParseLine, + NULL, + DEH_WeaponMD5Sum, +}; + 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..459c43dd --- /dev/null +++ b/src/strife/doomdef.h @@ -0,0 +1,297 @@ +// 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 + + +// 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), + 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), // Note: seems to be unused + + 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..b591358f --- /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_final; +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..8cb562b2 --- /dev/null +++ b/src/strife/doomstat.h @@ -0,0 +1,305 @@ +// 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_net.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 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 int viewwindowx; +extern int viewwindowy; +extern int viewheight; +extern int viewwidth; +extern int scaledviewwidth; + +extern boolean testcontrols; + + + + +// 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. + + + +extern int gametic; + + +// Bookkeeping on players - state. +extern player_t players[MAXPLAYERS]; + +// Alive? Disconnected? +extern boolean playeringame[MAXPLAYERS]; + + +// Player spawn spots for deathmatch. +#define MAX_DM_STARTS 10 +extern mapthing_t deathmatchstarts[MAX_DM_STARTS]; +extern mapthing_t* 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; + + +// LUT of ammunition limits for each kind. +// This doubles with BackPack powerup item. +extern int maxammo[NUMAMMO]; + + + + + +//----------------------------------------- +// Internal parameters, used for engine. +// + +// File handling stuff. +extern char * 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; +//? +// debug flag to cancel adaptiveness +extern boolean singletics; + +//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 int maketic; +extern int nettics[MAXPLAYERS]; + +extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; +extern int ticdup; + + + +#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..1761ad44 --- /dev/null +++ b/src/strife/f_finale.c @@ -0,0 +1,1015 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1996 Rogue Entertainment / Velocity, Inc. +// Copyright(C) 2005 Simon Howard +// 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: +// 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_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 +}; + +// +// F_StartFinale +// +// [STRIFE] +// haleyjd 09/13/10: Modified to drive slideshow sequences. +// +void F_StartFinale (void) +{ + patch_t *panel; + + gameaction = ga_nothing; + gamestate = GS_FINALE; + viewactive = false; + automapactive = false; + wipegamestate = -1; // [STRIFE] + + // [STRIFE] Setup the slide show + slideshow_panel = DEH_String("PANEL0"); + + panel = (patch_t *)W_CacheLumpName(slideshow_panel, PU_CACHE); + V_DrawPatch(0, 0, panel); + + 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; + 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 may in fact be unused. +// STRIFE-TODO: Determine if this is really used or not! +// +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("SS4F2"); + 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_EXITHACK: // state -99: super hack state + gamestate = GS_LEVEL; + P_DialogStartP1(); + break; + case SLIDE_EXIT: // state -1: proceed to next finale stage + finalecount = 0; + finalestage = F_STAGE_ARTSCREEN; + wipegamestate = -1; + S_StartMusic(mus_fast); + 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; + 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; + +extern gamestate_t wipegamestate; + +// +// 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; + static int laststage; + + 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..4c496f38 --- /dev/null +++ b/src/strife/f_wipe.c @@ -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: +// 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 + }; + + void V_MarkRect(int, int, int, int); + + // initial stuff + if (!go) + { + go = 1; + // 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); + // V_DrawBlock(x, y, 0, width, height, wipe_scr); // DEBUG + + // 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..c9d49c18 --- /dev/null +++ b/src/strife/g_game.c @@ -0,0 +1,2564 @@ +// 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 + +boolean G_CheckDemoStatus (void); +void G_ReadDemoTiccmd (ticcmd_t* cmd); +void G_WriteDemoTiccmd (ticcmd_t* cmd); +void G_PlayerReborn (int player); +void G_InitNew (skill_t skill, int map); + +void G_DoReborn (int playernum); + +void G_DoLoadLevel (void); +void G_DoNewGame (void); +void G_DoLoadGame (boolean userload); +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_elecbow, wp_elecbow }, + { wp_poisonbow, wp_elecbow }, + { wp_rifle, wp_rifle }, + { wp_missile, wp_missile }, + { wp_hegrenade, wp_hegrenade }, + { wp_wpgrenade, wp_hegrenade }, + { wp_flame, wp_flame }, + { wp_mauler, wp_mauler }, + { wp_torpedo, 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]; + +static int testcontrols_mousespeed; + +#define BODYQUESIZE 32 + +mobj_t* bodyque[BODYQUESIZE]; +//int bodyqueslot; [STRIFE] unused + +int vanilla_savegame_limit = 1; +int vanilla_demo_limit = 1; + + +#define MOUSE_SPEED_BOX_WIDTH 16 +#define COLOR_RED 0xb0 +#define COLOR_BLACK 0x00 +#define COLOR_WHITE 0x04 +#define COLOR_YELLOW 0xe7 + +void G_DrawMouseSpeedBox(void) +{ + extern int usemouse; + int i; + int box_x, box_y; + int original_speed; + int x, y; + int redline_x; + int linelen; + char *lumpname; + int color; + + // If the mouse is turned off or acceleration is turned off, don't + // draw the box at all. + + if (!usemouse || fabs(mouse_acceleration - 1) < 0.01) + { + return; + } + + // Calculate box position + + box_x = SCREENWIDTH - MOUSE_SPEED_BOX_WIDTH * 8; + box_y = SCREENHEIGHT - 9; + + // Draw the box. + + x = box_x; + + for (i=0; i<MOUSE_SPEED_BOX_WIDTH; ++i) + { + if (i == 0) + { + lumpname = "M_LSLEFT"; + } + else if (i == MOUSE_SPEED_BOX_WIDTH - 1) + { + lumpname = "M_LSRGHT"; + } + else + { + lumpname = "M_LSCNTR"; + } + + V_DrawPatchDirect(x, box_y, + W_CacheLumpName(DEH_String(lumpname), PU_CACHE)); + x += 8; + } + + // Calculate the position of the red line. This is 1/3 of the way + // along the box. + + redline_x = (MOUSE_SPEED_BOX_WIDTH / 3) * 8; + + // Undo acceleration and get back the original mouse speed + + if (testcontrols_mousespeed < mouse_threshold) + { + original_speed = testcontrols_mousespeed; + } + else + { + original_speed = testcontrols_mousespeed - mouse_threshold; + original_speed = (int) (original_speed / mouse_acceleration); + original_speed += mouse_threshold; + } + + // Calculate line length + + linelen = (original_speed * redline_x) / mouse_threshold; + + // Draw horizontal "thermometer" + + for (x=0; x<(MOUSE_SPEED_BOX_WIDTH - 1) * 8; ++x) + { + if (x < linelen) + { + if (x < redline_x) + { + color = COLOR_WHITE; + } + else + { + color = COLOR_YELLOW; + } + } + else + { + color = COLOR_BLACK; + } + + I_VideoBuffer[(box_y - 4) * SCREENWIDTH + box_x + x + 1] = color; + } + + // Draw red line + + for (y=box_y - 8; y<box_y; ++y) + { + I_VideoBuffer[y * SCREENWIDTH + box_x + redline_x] = COLOR_RED; + } +} + +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) +{ + // Can't select a weapon if we don't own it. + + if (!players[consoleplayer].weaponowned[weapon]) + { + return false; + } + + // STRIFE-TODO: Special weapon cycling rules? + + 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 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] TODO - 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 +// +extern gamestate_t wipegamestate; + +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][buf], 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-TODO: not quite sure why it does this + 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; +} + +// The sky texture to be used instead of the F_SKY1 dummy. +extern int skytexture; + +// +// 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]; + + // STRIFE-TODO: TEMPORARY: fill out the rest of playeringame until + // MAXPLAYERS == 8 + for (; i < 8; i++) + *demo_p++ = 0; +} + + +// +// 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++; + + // STRIFE-TODO: read out the rest of playeringame until + // MAXPLAYERS is bumped to 8 + for(; i < 8; 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"); + + // haleyjd: STRIFE-TODO: where's -noblit? + + 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..62bb000e --- /dev/null +++ b/src/strife/g_game.h @@ -0,0 +1,98 @@ +// 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); + +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..2033c7b5 --- /dev/null +++ b/src/strife/hu_lib.c @@ -0,0 +1,478 @@ +// 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 09/18/10: [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; + } + else if(c == '_' || c != ' ' || x != start_x) + { + 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; + static boolean lastautomapactive = true; + + // 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 + } + } + } + + lastautomapactive = automapactive; + 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..42a9dbb1 --- /dev/null +++ b/src/strife/hu_stuff.c @@ -0,0 +1,662 @@ +// 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; +extern boolean automapactive; + +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; + + if (headsupactive) + HU_Stop(); + + 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 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++)); + + // 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; + } + + 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 shiftdown = false; + static boolean altdown = false; + unsigned char c; + int i; + int numplayers; + + static int num_nobrainers = 0; + + numplayers = 0; + for (i=0 ; i<MAXPLAYERS ; i++) + numplayers += playeringame[i]; + + if (ev->data1 == KEY_RSHIFT) + { + shiftdown = ev->type == ev_keydown; + 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..4d16e3e8 --- /dev/null +++ b/src/strife/m_menu.c @@ -0,0 +1,2314 @@ +// 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; + +// 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; + +// +// 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_QuitStrife(int choice); + +void M_ChangeMessages(int choice); +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_LoadSelect(int choice); +void M_SaveSelect(int choice); +void M_ReadSaveStrings(void); +void M_QuickSave(void); +void M_QuickLoad(void); + +void M_DrawMainMenu(void); +void M_DrawReadThis1(void); +void M_DrawReadThis2(void); +void M_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_StartControlPanel(void); +void M_StartMessage(char *string,void *routine,boolean input); +void M_StopMessage(void); +void M_ClearMenus (int choice); + + + + +// +// 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 count; + 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; + } + count = 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; + + sendsave = 1; + ClearTmp(); + G_WriteSaveName(choice, savegamestrings[choice]); + quickSaveSlot = choice; // VERIFY VARIABLE + 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) +{ + /* + char name[256]; + + strcpy(name, P_SaveGameFile(choice)); + + G_LoadGame (name); + M_ClearMenus (0); + */ + + // [STRIFE] (v1.2) - TODO: v1.31 + char *name = NULL; + + G_WriteSaveName(choice, savegamestrings[choice]); + ToCurr(); + + 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 (v1.2) - TODO: v1.31 +// +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) +{ + /* + G_SaveGame (slot,savegamestrings[slot]); + M_ClearMenus (0); + + // PICK QUICKSAVE SLOT YET? + if (quickSaveSlot == -2) + quickSaveSlot = slot; + */ + // [STRIFE] (v1.2) - TODO: v1.31 + 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] (v1.2) - TODO: 1.31 + 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] (v1.2) - TODO: v1.31 + 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] (v1.2) - TODO: v1.31 + //M_SetupNextMenu(&SaveDef); + 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 (v1.2) - TODO: v1.31 +// +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; + } + + // STRIFE-TODO: Voice volume setting + //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 + M_SetupNextMenu(&NewDef); +} + + +// +// M_Episode +// +int epi; + +void M_DrawEpisode(void) +{ + V_DrawPatchDirect(54, 38, W_CacheLumpName(DEH_String("M_EPISOD"), PU_CACHE)); +} + +/* +// haleyjd: [STRIFE] Unused +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 +// +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); +} +*/ + + +// +// 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; + + // "close" button pressed on window? + if (ev->type == ev_quit) + { + 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; + + // In testcontrols mode, none of the function keys should do anything + // - the only key is escape to quit. + + if (testcontrols) + { + if (key == key_menu_activate || key == key_menu_quit) + { + I_Quit(); + return true; + } + + 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] v1.2 - TODO: v1.31 + saveStringEnter = 0; + 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 a different button and quicksave + // functionality is restored separate from normal saving (STRIFE-TODO) + /* + 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 + { + /* + M_StartControlPanel(); + S_StartSound(NULL, sfx_swtchn); + M_SaveGame(0); + */ + // [STRIFE] (v1.2) - TODO: v1.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 + { + /* + M_StartControlPanel(); + S_StartSound(NULL, sfx_swtchn); + M_LoadGame(0); + */ + // [STRIFE] (v1.2) - TODO: v1.31 + 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; + } + // STRIFE-TODO: autouse health toggle + else if (key == key_menu_qsave) // Quicksave + { + //S_StartSound(NULL, sfx_swtchn); + //M_QuickSave(); + // [STRIFE] (v1.2) - TODO: v1.31 + 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... (STRIFE-TODO) + /* + S_StartSound(NULL, sfx_swtchn); + M_QuickLoad(); + */ + 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; + } + } + + // 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(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] TODO - fix 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..186cef21 --- /dev/null +++ b/src/strife/m_saves.c @@ -0,0 +1,533 @@ +// 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
+//
+//-----------------------------------------------------------------------------
+
+// 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, 300, 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;
+
+ // 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..ec07eeaf --- /dev/null +++ b/src/strife/p_ceilng.c @@ -0,0 +1,347 @@ +// 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. +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 = §ors[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: + 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..77d48c0e --- /dev/null +++ b/src/strife/p_dialog.c @@ -0,0 +1,1413 @@ +// 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
+//
+// 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_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.
+boolean 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.
+player_t *dialogplayer;
+
+// The object to which the player is speaking.
+mobj_t *dialogtalker;
+
+// The talker's current angle
+angle_t dialogtalkerangle;
+
+// The currently active mapdialog object.
+static mapdialog_t *currentdialog;
+
+// Text at the end of the choices
+char dialoglastmsgbuffer[48];
+
+// Item to display to player when picked up or recieved
+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 PLANES 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 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.",
+
+ "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;
+ boolean ok = true;
+ 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: // STRIFE-TODO: verify - I believe this is related to a cheat
+ 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];
+
+ // 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)
+ {
+ DEH_snprintf(choicetext, sizeof(choicetext),
+ "%s for %d",
+ choicetext,
+ 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);
+ }
+ 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 j = 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 = 0;
+ menuindialog = 1;
+ 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..66a3b0a8 --- /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 boolean 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..850baac6 --- /dev/null +++ b/src/strife/p_doors.c @@ -0,0 +1,1383 @@ +// 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 = §ors[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; + int rtn; + sector_t* sec; + int i; + line_t* secline; + boolean ret = false; + + secnum = -1; + rtn = 0; + + while((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + rtn = 1; + + 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; + int secnum; + 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; + secnum = sec-sectors; + + 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 = §ors[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..9cbaf3ed --- /dev/null +++ b/src/strife/p_enemy.c @@ -0,0 +1,3354 @@ +// 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 09/10/10: Hex-Rays was leaving this out completely: + if (actor->type == MT_CRUSADER && dist > 120) + dist = 120; + + if (P_Random () < dist) + return false; + + return true; +} + +// +// 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; + + // randomly determine direction of search + if(P_Random() & 1) + { + for(dir = 0; dir < DI_NODIR; dir++) + { + if(dir != opposite[actor->movedir]) + { + actor->movedir = dir; + if(P_Random() & 1) + { + if(P_TryWalk(actor)) + break; + } + } + } + } + else + { + dir = DI_SOUTHEAST; + while(1) + { + // haleyjd 09/05/10: missing random code. + if(dir != opposite[actor->movedir]) + { + actor->movedir = dir; + + // villsa 09/06/10: un-inlined code + if(P_TryWalk(actor)) + return; + } + + if(--dir == -1) + { + if(opposite[actor->movedir] == DI_NODIR) + { + actor->movedir = DI_NODIR; + return; + } + + actor->movedir = opposite[actor->movedir]; + + // 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; + sector_t* sector; + 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; + } + + sector = actor->subsector->sector; + + c = 0; + stop = (actor->lastlook-1)&3; + + for ( ; ; actor->lastlook = (actor->lastlook+1)&3 ) + { + 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] not used + /*if(gametic & 3) + return;*/ + + // spawn a puff of smoke behind the rocket + /*P_SpawnPuff(actor->x, actor->y, actor->z); + + th = P_SpawnMobj (actor->x-actor->momx, + actor->y-actor->momy, + actor->z, MT_SMOKE); + + th->momz = FRACUNIT; + th->tics -= P_Random()&3; + if (th->tics < 1) + th->tics = 1;*/ + + // adjust direction + dest = actor->tracer; + + if(!dest || dest->health <= 0) + return; + + // change angle + exact = R_PointToAngle2(actor->x, actor->y, dest->x, dest->y); + + if(exact != actor->angle) + { + // 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)) + { + S_StartSound(actor, sfx_mtalht); + P_DamageMobj(actor->target, actor, actor, 8 * (P_Random() % 10 + 1)); + } + +} + +// 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 INCOMBAT, 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 +// +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); + + 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) // [STRIFE] TODO - verify + 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 +// +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 +// +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 +// +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 + + x = actor->x + (((P_Random() + 12) & 31) << FRACBITS); + y = actor->y + (((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..df966d28 --- /dev/null +++ b/src/strife/p_floor.c @@ -0,0 +1,587 @@ +// 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 +// +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) + { + // villsa [STRIFE] unused + //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 = §ors[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 = §ors[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..10559d8f --- /dev/null +++ b/src/strife/p_inter.c @@ -0,0 +1,1401 @@ +// 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 09/23/10: fixed to give proper amount of health + { + // 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. + player->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. 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] TODO - verify this. Seems that questflag isn't + // applied if the special's speed is equal to 8 or if + // the player has received a specific quest token + if(special->info->speed != 8 || !(player->questflags & QF_QUEST6)) + player->questflags |= 1 << (special->info->speed - 1); + } + + + // 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[76]; + +// +// 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] unused + /* + target->tics -= P_Random()&3; + if (target->tics < 1) + target->tics = 1; + */ + + // 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; + } + + players[i].weaponowned[wp_sigil] = true; + players[i].readyweapon = 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 + 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..5ea03903 --- /dev/null +++ b/src/strife/p_lights.c @@ -0,0 +1,358 @@ +// 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 +// +void T_FireFlicker (fireflicker_t* flick) +{ + int amount; + + if (--flick->count) + return; + + amount = (P_Random()&3)*16; + + if (flick->sector->lightlevel - amount < flick->minlight) + flick->sector->lightlevel = flick->minlight; + else + flick->sector->lightlevel = flick->maxlight - amount; + + flick->count = 4; +} + + + +// +// P_SpawnFireFlicker +// +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 = P_FindMinSurroundingLight(sector,sector->lightlevel)+16; + flick->count = 4; +} + + + +// +// BROKEN LIGHT FLASHING +// + + +// +// T_LightFlash +// Do flashing lights. +// +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 +// +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 +// +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 +// +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) +// +void EV_StartLightStrobing(line_t* line) +{ + int secnum; + sector_t* sec; + + secnum = -1; + while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) + { + sec = §ors[secnum]; + if (sec->specialdata) + continue; + + P_SpawnStrobeFlash (sec,SLOWDARK, 0); + } +} + + + +// +// TURN LINE'S TAG LIGHTS OFF +// +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 +// +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 +// + +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; + } +} + + +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..c557f968 --- /dev/null +++ b/src/strife/p_map.c @@ -0,0 +1,1668 @@ +// 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 + /*if (tmthing->flags & MF_SKULLFLY) + { + damage = ((P_Random()%8)+1)*tmthing->info->damage; + + P_DamageMobj (thing, tmthing, tmthing, damage); + + tmthing->flags &= ~MF_SKULLFLY; + tmthing->momx = tmthing->momy = tmthing->momz = 0; + + P_SetMobjState (tmthing, tmthing->info->spawnstate); + + return false; // stop moving + }*/ + + // missiles can hit other things + 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..f20295b8 --- /dev/null +++ b/src/strife/p_mobj.c @@ -0,0 +1,1377 @@ +// 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] unused + /* + mo->tics -= P_Random()&3; + + if (mo->tics < 1) + mo->tics = 1; + */ + + 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 +// +#define STOPSPEED 0x1000 +#define FRICTION 0xe800 + +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 + if(blockingline && blockingline->special) + P_ShootSpecialLine(mo, blockingline); + if(numspechit) + P_ShootSpecialLine(mo, spechit[numspechit]); + + // 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 + + if (mo->z > mo->floorz) + 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 02/02/11) + 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 + + // Note (id): + // somebody left this after the setting momz to 0, + // kinda useless there. + // + // cph - This was the a bug in the linuxdoom-1.10 source which + // caused it not to sync Doom 2 v1.9 demos. Someone + // added the above comment and moved up the following code. So + // demos would desync in close lost soul fights. + // Note that this only applies to original Doom 1 or Doom2 demos - not + // Final Doom and Ultimate Doom. So we test demo_compatibility *and* + // gamemission. (Note we assume that Doom1 is always Ult Doom, which + // seems to hold for most published demos.) + // + // fraggle - cph got the logic here slightly wrong. There are three + // versions of Doom 1.9: + // + // * The version used in registered doom 1.9 + doom2 - no bounce + // * The version used in ultimate doom - has bounce + // * The version used in final doom - has bounce + // + // So we need to check that this is either retail or commercial + // (but not doom2) + + // [STRIFE] not applicable + //int correct_lost_soul_bounce = gameversion >= exe_ultimate; + + if (/*correct_lost_soul_bounce &&*/ 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 + if(mo->momz < -20*FRACUNIT) + { + // haleyjd 09/18/10: Repaired calculation + P_DamageMobj(mo, NULL, mo, mo->momz / -25000); + 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); + return; + } + } + else 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); + + return; + } + } +} + + + +// +// 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); + + // 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 +// +// STRIFE-FIXME/STRIFE-TODO: +// * 8-player support +// * Restore I_Error for missing mapthings (8-player support is prerequisite) +// +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 + // STRIFE-TODO: Need 8 player starts + if (mthing->type <= 4) + { + // 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); + */ + // haleyjd 08/29/10: STRIFE-FIXME: Temporarily disabled I_Error for testing purposes + if (i == NUMMOBJTYPES) + return; + + // 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 = P_Random(); + + z += ((t - P_Random()) << 10); + + // [STRIFE] Unused + //th->momz = FRACUNIT; + //th->tics -= P_Random()&3; + + 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 = P_Random(); + z += (temp - P_Random()) << 10; + th = P_SpawnMobj(x, y, z, MT_BLOOD_DEATH); + th->momz = FRACUNIT*2; + + // villsa [STRIFE] unused + /* + th->tics -= P_Random()&3; + + if (th->tics < 1) + th->tics = 1; + */ + + // 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] unused + /* + th->tics -= P_Random()&3; + if (th->tics < 1) + th->tics = 1; + */ + + // move a little forward so an angle can + // be computed if it immediately explodes + th->x += (th->momx>>1); + th->y += (th->momy>>1); + th->z += (th->momz>>1); + + 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) + an += (P_Random()-P_Random())<<21; + // villsa [STRIFE] check for heavily transparent things + else if(dest->flags & MF_MVIS) + an += (P_Random()-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 = §ors[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..42a6bd7b --- /dev/null +++ b/src/strife/p_pspr.c @@ -0,0 +1,1009 @@ +// 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; + P_DamageMobj(player->mo, player->mo, 0, 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..2dc779f9 --- /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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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 = §ors[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..e26d9144 --- /dev/null +++ b/src/strife/p_spec.c @@ -0,0 +1,2002 @@ +// 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 pic = 0; + 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-TODO: Identify type + case 195: // haleyjd: STRIFE-TODO: Identify type + case 231: // haleyjd: STRIFE-TODO: Identify type + 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 = §ors[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; + int episode; + + episode = 1; + if (W_CheckNumForName(DEH_String("texture2")) >= 0) + episode = 2; + + // 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: // [STRIFE] TODO: verify scroll types + 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..9234c00d --- /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..fa521ace --- /dev/null +++ b/src/strife/p_user.c @@ -0,0 +1,932 @@ +// 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] + + +boolean P_UseInventoryItem(player_t* player, int item); // fraggle [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] TODO - 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); + break; + + case SPR_ARM2: // 137 + return P_GiveArmor(player, 1); + break; + + case SPR_SHD1: // 186 + return P_GivePower(player, pw_invisibility); + break; + + case SPR_MASK: // 187 + return P_GivePower(player, pw_ironfeet); + break; + + 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; + break; + + case SPR_STMP: // 180 + return P_GiveBody(player, 10); + break; + + case SPR_MDKT: // 181 + return P_GiveBody(player, 25); + break; + + case SPR_FULL: // 130 + return P_GiveBody(player, 200); + break; + + case SPR_BEAC: // 135 + return P_SpawnTeleportBeacon(player); + break; + + case SPR_TARG: // 108 + return P_GivePower(player, pw_targeter); + break; + } + + 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..46138c85 --- /dev/null +++ b/src/strife/r_data.c @@ -0,0 +1,1034 @@ +// 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; + byte* dest; + + dest = (byte *)cache + 3; + + 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, length; + + // Load in the light tables, + // 256 byte align tables. + lump = W_GetNumForName(DEH_String("COLORMAP")); + length = W_LumpLength (lump); + 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); + //memcpy(&v6, texture->index, 0); // [STRIFE] todo - WHAT?! + + 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..d6c6b6f9 --- /dev/null +++ b/src/strife/r_draw.c @@ -0,0 +1,985 @@ +// 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--); +} + + +// haleyjd 08/26/10: [STRIFE] - Rogue's translucency lookup table +// This is functionally equivalent to Raven's TINTTAB and BOOM's TRANMAPs. +extern byte *xlatab; + +// +// 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) + -128; + 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); + } + 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<= 0x40) + { + 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 +V_MarkRect +( int x, + int y, + int width, + int height ); + +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..0a8a639b --- /dev/null +++ b/src/strife/r_main.c @@ -0,0 +1,954 @@ +// 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 "d_net.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++) + { + dy = ((i-viewheight/2)<<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..edc5dbbb --- /dev/null +++ b/src/strife/r_main.h @@ -0,0 +1,170 @@ +// 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 viewwidth; +extern int viewheight; +extern int viewwindowx; +extern int viewwindowy; + + + +extern int centerx; +extern int centery; + +extern fixed_t centerxfrac; +extern fixed_t centeryfrac; +extern fixed_t projection; + +extern int validcount; + +extern int linecount; +extern int loopcount; + + +// +// 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..bda7a81c --- /dev/null +++ b/src/strife/r_things.c @@ -0,0 +1,1063 @@ +// 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]; + flip = (boolean)sprframe->flip[0]; + + // calculate edges of the shape + tx = psp->sx-160*FRACUNIT; + + tx -= spriteoffset[lump]; + x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS; + + // off the right side + if (x1 > viewwidth) + return; + + tx += spritewidth[lump]; + x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1; + + // off the left side + if (x2 < 0) + return; + + // store information in a vissprite + vis = &avis; + vis->mobjflags = 0; + 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..c29ce392 --- /dev/null +++ b/src/strife/s_sound.c @@ -0,0 +1,835 @@ +// 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: 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. +// + +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); + + if (gamemap != 8 && 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 + if (approx_dist < S_CLOSE_DIST) + { + *vol = snd_SfxVolume; + } + else if (gamemap == 8) + { + if (approx_dist > S_CLIPPING_DIST) + { + approx_dist = S_CLIPPING_DIST; + } + + *vol = 15+ ((snd_SfxVolume-15) + *((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) + / S_ATTENUATOR; + } + 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 priority; + int cnum; + int volume; + + origin = (mobj_t *) origin_p; + volume = snd_SfxVolume; + + // check for bogus sound # + if (sfx_id < 1 || sfx_id > NUMSFX) + { + I_Error("Bad sfx #: %d", sfx_id); + } + + sfx = &S_sfx[sfx_id]; + + // Initialize sound parameters + if (sfx->link) + { + priority = sfx->priority; + volume += sfx->volume; + + if (volume < 1) + { + return; + } + + if (volume > snd_SfxVolume) + { + volume = snd_SfxVolume; + } + } + else + { + priority = NORM_PRIORITY; + } + + + // 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 + //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..314962c2 --- /dev/null +++ b/src/strife/st_stuff.c @@ -0,0 +1,1585 @@ +// 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 + +// Weapon pos. +#define ST_ARMSX 111 +#define ST_ARMSY 172 +#define ST_ARMSBGX 104 +#define ST_ARMSBGY 168 +#define ST_ARMSXSPACE 12 +#define ST_ARMSYSPACE 10 + +// Frags pos. +#define ST_FRAGSX 138 +#define ST_FRAGSY 171 +#define ST_FRAGSWIDTH 2 + +// ARMOR number pos. +#define ST_ARMORWIDTH 3 +#define ST_ARMORX 221 +#define ST_ARMORY 171 + +// Key icon positions. +#define ST_KEY0WIDTH 8 +#define ST_KEY0HEIGHT 5 +#define ST_KEY0X 239 +#define ST_KEY0Y 171 +#define ST_KEY1WIDTH ST_KEY0WIDTH +#define ST_KEY1X 239 +#define ST_KEY1Y 181 +#define ST_KEY2WIDTH ST_KEY0WIDTH +#define ST_KEY2X 239 +#define ST_KEY2Y 191 + +// Ammunition counter. +#define ST_AMMO0WIDTH 3 +#define ST_AMMO0HEIGHT 6 +#define ST_AMMO0X 288 +#define ST_AMMO0Y 173 +#define ST_AMMO1WIDTH ST_AMMO0WIDTH +#define ST_AMMO1X 288 +#define ST_AMMO1Y 179 +#define ST_AMMO2WIDTH ST_AMMO0WIDTH +#define ST_AMMO2X 288 +#define ST_AMMO2Y 191 +#define ST_AMMO3WIDTH ST_AMMO0WIDTH +#define ST_AMMO3X 288 +#define ST_AMMO3Y 185 + +// Indicate maximum ammunition. +// Only needed because backpack exists. +#define ST_MAXAMMO0WIDTH 3 +#define ST_MAXAMMO0HEIGHT 5 +#define ST_MAXAMMO0X 314 +#define ST_MAXAMMO0Y 173 +#define ST_MAXAMMO1WIDTH ST_MAXAMMO0WIDTH +#define ST_MAXAMMO1X 314 +#define ST_MAXAMMO1Y 179 +#define ST_MAXAMMO2WIDTH ST_MAXAMMO0WIDTH +#define ST_MAXAMMO2X 314 +#define ST_MAXAMMO2Y 191 +#define ST_MAXAMMO3WIDTH ST_MAXAMMO0WIDTH +#define ST_MAXAMMO3X 314 +#define ST_MAXAMMO3Y 185 + +// pistol +#define ST_WEAPON0X 110 +#define ST_WEAPON0Y 172 + +// shotgun +#define ST_WEAPON1X 122 +#define ST_WEAPON1Y 172 + +// chain gun +#define ST_WEAPON2X 134 +#define ST_WEAPON2Y 172 + +// missile launcher +#define ST_WEAPON3X 110 +#define ST_WEAPON3Y 181 + +// plasma gun +#define ST_WEAPON4X 122 +#define ST_WEAPON4Y 181 + + // bfg +#define ST_WEAPON5X 134 +#define ST_WEAPON5Y 181 + +// WPNS title +#define ST_WPNSX 109 +#define ST_WPNSY 191 + + // DETH title +#define ST_DETHX 109 +#define ST_DETHY 191 + +// 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-TODO: This is handled differently +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("idkfa", 0); // STRIFE-TODO +cheatseq_t cheat_ammonokey = CHEAT("idfa", 0); // STRIFE-TODO +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_powerup[7] = // STRIFE-TODO +{ + CHEAT("idbeholdv", 0), + CHEAT("idbeholds", 0), + CHEAT("idbeholdi", 0), + CHEAT("idbeholdr", 0), + CHEAT("idbeholda", 0), + CHEAT("idbeholdl", 0), + CHEAT("idbehold", 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[52]; + +// 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; + + // villsa [STRIFE] TODO - verify this logic + 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-TODO: "dev" cheat - is this the "DOTS" cheat? + 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->message = DEH_String(STSTR_DQDOFF); + } + // + // STRIFE-TODO: IDFA, IDKFA equivs are unfinished + // + else if (cht_CheckCheat(&cheat_ammonokey, ev->data2)) + { + // 'fa' cheat for killer fucking arsenal + plyr->armorpoints = deh_idfa_armor; + plyr->armortype = deh_idfa_armor_class; + + for (i=0;i<NUMWEAPONS;i++) + plyr->weaponowned[i] = true; + + for (i=0;i<NUMAMMO;i++) + plyr->ammo[i] = plyr->maxammo[i]; + + plyr->message = DEH_String(STSTR_FAADDED); + } + else if (cht_CheckCheat(&cheat_ammo, ev->data2)) + { + // 'kfa' cheat for key full ammo + plyr->armorpoints = deh_idkfa_armor; + plyr->armortype = deh_idkfa_armor_class; + + for (i=0;i<NUMWEAPONS;i++) + plyr->weaponowned[i] = true; + + for (i=0;i<NUMAMMO;i++) + plyr->ammo[i] = plyr->maxammo[i]; + + for (i=0;i<NUMCARDS;i++) + plyr->cards[i] = true; + + plyr->message = DEH_String(STSTR_KFAADDED); + } + + // villsa [STRIFE] + else if(cht_CheckCheat(&cheat_keys, ev->data2)) + { + #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; + } + } + + // villsa [STRIFE] + else if(cht_CheckCheat(&cheat_stealth, ev->data2)) + { + plyr->cheats ^= CF_NOMOMENTUM; + if(plyr->cheats & CF_NOMOMENTUM) + plyr->message = DEH_String("STEALTH BOOTS ON"); + else + plyr->message = DEH_String("STEALTH BOOTS OFF"); + } + + + // + // STRIFE-TODO: Fix idbehold equivalent + // + for (i=0;i<6;i++) + { + // 'behold?' power-up cheats + if (cht_CheckCheat(&cheat_powerup[i], ev->data2)) + { + if (!plyr->powers[i]) + P_GivePower( plyr, i); + else if (i!=pw_strength) + plyr->powers[i] = 1; + else + plyr->powers[i] = 0; + + plyr->message = DEH_String(STSTR_BEHOLDX); + } + } + // STRIFE-TODO: + if (cht_CheckCheat(&cheat_powerup[6], ev->data2)) + { + // 'behold' power-up menu + plyr->message = DEH_String(STSTR_BEHOLD); + } + + // + // STRIFE-TODO: + // * Give medical items cheat (what code???) + // * Ammo cheat + // * Stats cheat + // * Unknown power-giving cheat + /* + if(cht_CheckCheat(&cheat_meditems, ev->data2)) + { + 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(&off_885E4, ev->data2)) + { + 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_stats, ev->data2)) + { + 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!"); + } + // + // UNKNOWN POWER GIVING CHEAT HERE... + // + */ + + // STRIFE-TODO: weird isdemoversion check + + 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 + + // Ohmygod - this is not going to work. + 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); + } + } + + // villsa [STRIFE] + if(cht_CheckCheat(&cheat_nuke, ev->data2)) + { + stonecold ^= 1; + plyr->message = DEH_String("Kill 'em. Kill 'em All"); + } + + // 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] + if(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; // unknown var + + 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); + } +} + +void ST_diffDraw(void) +{ + // haleyjd: STRIFE-TODO: Needed? +} + +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(); + + // haleyjd 09/01/10: STRIFE-TODO: work out statbar details + + // If just after ST_Start(), refresh all + ST_doRefresh(); + // Otherwise, update as little as possible + ST_diffDraw(); +} + +// +// 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]; + + hours = time / 3600; + minutes = time / 60; + seconds = time % 60; + + DEH_snprintf(string, 16, "%02d:%02d:%02d", hours, minutes, seconds); + HUlib_drawYellowText(x, y, string); +} + +// +// 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] TODO + if(st_showkeys || st_popupdisplaytics) + return true; // temp + //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)); + } + + // STRIFE-TODO: DRAW AMMO PICS + + 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) +{ + // 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 08/31/10: [STRIFE] + // * No face. + // 09/01/10: + // * No arms, weaponsowned, frags, armor, keyboxes + + // haleyjd 09/01/10: STRIFE-TODO: Ammo Widgets!!! + /* + // ammo count (all four kinds) + STlib_initNum(&w_ammo[0], + ST_AMMO0X, + ST_AMMO0Y, + shortnum, + &plyr->ammo[0], + &st_statusbaron, + ST_AMMO0WIDTH); + + STlib_initNum(&w_ammo[1], + ST_AMMO1X, + ST_AMMO1Y, + shortnum, + &plyr->ammo[1], + &st_statusbaron, + ST_AMMO1WIDTH); + + STlib_initNum(&w_ammo[2], + ST_AMMO2X, + ST_AMMO2Y, + shortnum, + &plyr->ammo[2], + &st_statusbaron, + ST_AMMO2WIDTH); + + STlib_initNum(&w_ammo[3], + ST_AMMO3X, + ST_AMMO3Y, + shortnum, + &plyr->ammo[3], + &st_statusbaron, + ST_AMMO3WIDTH); + + // max ammo count (all four kinds) + STlib_initNum(&w_maxammo[0], + ST_MAXAMMO0X, + ST_MAXAMMO0Y, + shortnum, + &plyr->maxammo[0], + &st_statusbaron, + ST_MAXAMMO0WIDTH); + + STlib_initNum(&w_maxammo[1], + ST_MAXAMMO1X, + ST_MAXAMMO1Y, + shortnum, + &plyr->maxammo[1], + &st_statusbaron, + ST_MAXAMMO1WIDTH); + + STlib_initNum(&w_maxammo[2], + ST_MAXAMMO2X, + ST_MAXAMMO2Y, + shortnum, + &plyr->maxammo[2], + &st_statusbaron, + ST_MAXAMMO2WIDTH); + + STlib_initNum(&w_maxammo[3], + ST_MAXAMMO3X, + ST_MAXAMMO3Y, + shortnum, + &plyr->maxammo[3], + &st_statusbaron, + ST_MAXAMMO3WIDTH); + */ +} + +static boolean st_stopped = true; + + +void ST_Start (void) +{ + if (!st_stopped) + ST_Stop(); + + ST_initData(); + ST_createWidgets(); + st_stopped = false; +} + +void ST_Stop (void) +{ + if (st_stopped) + return; + + 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..0223108c --- /dev/null +++ b/src/strife/st_stuff.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: +// 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; + + +boolean ST_Responder(event_t* ev); + +extern byte *st_backing_screen; +extern cheatseq_t cheat_mus; +extern cheatseq_t cheat_god; +extern cheatseq_t cheat_ammo; +extern cheatseq_t cheat_ammonokey; +extern cheatseq_t cheat_noclip; +extern cheatseq_t cheat_commercial_noclip; +extern cheatseq_t cheat_powerup[7]; +extern cheatseq_t cheat_choppers; +extern cheatseq_t cheat_clev; +extern cheatseq_t cheat_mypos; + + +#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 diff --git a/src/v_video.c b/src/v_video.c index 6549a81b..3d874d6c 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -48,12 +48,18 @@ byte *tinttable = NULL; +// villsa [STRIFE] Blending table used for Strife +byte *xlatab = NULL; + // The screen buffer that the v_video.c code draws to. static byte *dest_screen = NULL; int dirtybox[4]; +// haleyjd 08/28/10: clipping callback function for patches. +// This is needed for Chocolate Strife, which clips patches to the screen. +static vpatchclipfunc_t patchclip_callback = NULL; // // V_MarkRect @@ -108,6 +114,20 @@ void V_CopyRect(int srcx, int srcy, byte *source, } } +// +// V_SetPatchClipCallback +// +// haleyjd 08/28/10: Added for Strife support. +// By calling this function, you can setup runtime error checking for patch +// clipping. Strife never caused errors by drawing patches partway off-screen. +// Some versions of vanilla DOOM also behaved differently than the default +// implementation, so this could possibly be extended to those as well for +// accurate emulation. +// +void V_SetPatchClipCallback(vpatchclipfunc_t func) +{ + patchclip_callback = func; +} // // V_DrawPatch @@ -127,6 +147,13 @@ void V_DrawPatch(int x, int y, patch_t *patch) y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); + // haleyjd 08/28/10: Strife needs silent error checking here. + if(patchclip_callback) + { + if(!patchclip_callback(patch, x, y)) + return; + } + #ifdef RANGECHECK if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH @@ -184,6 +211,13 @@ void V_DrawPatchFlipped(int x, int y, patch_t *patch) y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); + // haleyjd 08/28/10: Strife needs silent error checking here. + if(patchclip_callback) + { + if(!patchclip_callback(patch, x, y)) + return; + } + #ifdef RANGECHECK if (x < 0 || x + SHORT(patch->width) > SCREENWIDTH @@ -285,6 +319,55 @@ void V_DrawTLPatch(int x, int y, patch_t * patch) } // +// V_DrawXlaPatch +// +// villsa [STRIFE] Masks a column based translucent masked pic to the screen. +// + +void V_DrawXlaPatch(int x, int y, patch_t * patch) +{ + int count, col; + column_t *column; + byte *desttop, *dest, *source; + int w; + + y -= SHORT(patch->topoffset); + x -= SHORT(patch->leftoffset); + + if(patchclip_callback) + { + if(!patchclip_callback(patch, x, y)) + return; + } + + col = 0; + desttop = dest_screen + y * SCREENWIDTH + x; + + w = SHORT(patch->width); + for(; col < w; x++, col++, desttop++) + { + column = (column_t *) ((byte *) patch + LONG(patch->columnofs[col])); + + // 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 = xlatab[*dest + ((*source) << 8)]; + source++; + dest += SCREENWIDTH; + } + column = (column_t *) ((byte *) column + column->length + 4); + } + } +} + +// // V_DrawAltTLPatch // // Masks a column based translucent masked pic to the screen. @@ -400,6 +483,17 @@ void V_LoadTintTable(void) } // +// V_LoadXlaTable +// +// villsa [STRIFE] Load xla table from XLATAB lump. +// + +void V_LoadXlaTable(void) +{ + xlatab = W_CacheLumpName("XLATAB", PU_STATIC); +} + +// // V_DrawBlock // Draw a linear block of pixels into the view buffer. // diff --git a/src/v_video.h b/src/v_video.h index 0c722478..01791d6c 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -46,6 +46,13 @@ extern int dirtybox[4]; extern byte *tinttable; +// haleyjd 08/28/10: implemented for Strife support +// haleyjd 08/28/10: Patch clipping callback, implemented to support Choco +// Strife. +typedef boolean (*vpatchclipfunc_t)(patch_t *, int, int); +void V_SetPatchClipCallback(vpatchclipfunc_t func); + + // Allocates buffer screens, call before R_Init. void V_Init (void); @@ -60,7 +67,7 @@ void V_DrawPatchFlipped(int x, int y, patch_t *patch); void V_DrawTLPatch(int x, int y, patch_t *patch); void V_DrawAltTLPatch(int x, int y, patch_t * patch); void V_DrawShadowedPatch(int x, int y, patch_t *patch); - +void V_DrawXlaPatch(int x, int y, patch_t * patch); // villsa [STRIFE] void V_DrawPatchDirect(int x, int y, patch_t *patch); // Draw a linear block of pixels into the view buffer. @@ -92,5 +99,11 @@ void V_ScreenShot(char *format); void V_LoadTintTable(void); +// villsa [STRIFE] +// Load the lookup table for translucency calculations from the XLATAB +// lump. + +void V_LoadXlaTable(void); + #endif |