summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon Howard2010-09-09 23:13:06 +0000
committerSimon Howard2010-09-09 23:13:06 +0000
commit120d90c67b2a4aa0a8883c4897241dee2222acd2 (patch)
treeb439e48483ebbd698c2daa6e24eeaaab1ba97470 /src
parent79268587fc730e17cbd974a5583c7185604b59a3 (diff)
parent22fc405736dc4796958de221c07d52432f1b271b (diff)
downloadchocolate-doom-120d90c67b2a4aa0a8883c4897241dee2222acd2.tar.gz
chocolate-doom-120d90c67b2a4aa0a8883c4897241dee2222acd2.tar.bz2
chocolate-doom-120d90c67b2a4aa0a8883c4897241dee2222acd2.zip
Merge from raven-branch.
Subversion-branch: /branches/strife-branch Subversion-revision: 2051
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore4
-rw-r--r--src/Makefile.am14
-rw-r--r--src/deh_main.c10
-rw-r--r--src/deh_mapping.c140
-rw-r--r--src/deh_mapping.h22
-rw-r--r--src/deh_str.c227
-rw-r--r--src/deh_str.h9
-rw-r--r--src/doom/.gitignore4
-rw-r--r--src/doom/am_map.c6
-rw-r--r--src/doom/d_main.c196
-rw-r--r--src/doom/d_net.c10
-rw-r--r--src/doom/f_finale.c2
-rw-r--r--src/doom/g_game.c188
-rw-r--r--src/doom/hu_stuff.c14
-rw-r--r--src/doom/m_menu.c4
-rw-r--r--src/doom/p_saveg.c24
-rw-r--r--src/doom/p_saveg.h1
-rw-r--r--src/doom/p_setup.c100
-rw-r--r--src/doom/r_draw.c111
-rw-r--r--src/doom/s_sound.c9
-rw-r--r--src/doom/st_stuff.c22
-rw-r--r--src/doom/wi_stuff.c47
-rw-r--r--src/heretic/.gitignore7
-rw-r--r--src/heretic/Makefile.am13
-rw-r--r--src/heretic/am_map.c7
-rw-r--r--src/heretic/ct_chat.c13
-rw-r--r--src/heretic/d_main.c102
-rw-r--r--src/heretic/deh_ammo.c122
-rw-r--r--src/heretic/deh_frame.c344
-rw-r--r--src/heretic/deh_htext.c856
-rw-r--r--src/heretic/deh_htic.c186
-rw-r--r--src/heretic/deh_htic.h60
-rw-r--r--src/heretic/deh_sound.c118
-rw-r--r--src/heretic/deh_thing.c150
-rw-r--r--src/heretic/deh_weapon.c131
-rw-r--r--src/heretic/doomdef.h1
-rw-r--r--src/heretic/dstrings.h177
-rw-r--r--src/heretic/f_finale.c38
-rw-r--r--src/heretic/g_game.c21
-rw-r--r--src/heretic/in_lude.c73
-rw-r--r--src/heretic/info.c162
-rw-r--r--src/heretic/info.h15
-rw-r--r--src/heretic/mn_menu.c60
-rw-r--r--src/heretic/p_action.h160
-rw-r--r--src/heretic/p_doors.c7
-rw-r--r--src/heretic/p_inter.c75
-rw-r--r--src/heretic/p_pspr.c11
-rw-r--r--src/heretic/p_spec.c40
-rw-r--r--src/heretic/p_switch.c5
-rw-r--r--src/heretic/p_user.c3
-rw-r--r--src/heretic/r_data.c40
-rw-r--r--src/heretic/r_draw.c49
-rw-r--r--src/heretic/r_plane.c3
-rw-r--r--src/heretic/r_things.c14
-rw-r--r--src/heretic/s_sound.c21
-rw-r--r--src/heretic/sb_bar.c170
-rw-r--r--src/heretic/sounds.h5
-rw-r--r--src/hexen/.gitignore6
-rw-r--r--src/hexen/h2_main.c28
-rw-r--r--src/hexen/mn_menu.c47
-rw-r--r--src/hexen/p_acs.c2
-rw-r--r--src/hexen/p_spec.c2
-rw-r--r--src/hexen/r_things.c5
-rw-r--r--src/hexen/s_sound.c16
-rw-r--r--src/i_oplmusic.c1464
-rw-r--r--src/i_scale.c14
-rw-r--r--src/i_sdlmusic.c2
-rw-r--r--src/i_sdlsound.c72
-rw-r--r--src/i_sound.c10
-rw-r--r--src/i_video.c281
-rw-r--r--src/i_video.h4
-rw-r--r--src/m_argv.c2
-rw-r--r--src/m_config.c132
-rw-r--r--src/m_controls.c47
-rw-r--r--src/m_controls.h17
-rw-r--r--src/m_misc.c34
-rw-r--r--src/m_misc.h2
-rw-r--r--src/midifile.c814
-rw-r--r--src/midifile.h175
-rw-r--r--src/net_client.c3
-rw-r--r--src/setup/.gitignore3
-rw-r--r--src/setup/joystick.c2
-rw-r--r--src/setup/keyboard.c27
-rw-r--r--src/setup/keyboard.h53
-rw-r--r--src/setup/mainmenu.c60
-rw-r--r--src/setup/mouse.c9
-rw-r--r--src/setup/multiplayer.c35
-rw-r--r--src/setup/sound.c37
-rw-r--r--src/setup/txt_keyinput.c2
-rw-r--r--src/setup/txt_mouseinput.c4
-rw-r--r--src/strife/.gitignore4
-rw-r--r--src/strife/am_map.c6
-rw-r--r--src/strife/d_main.c196
-rw-r--r--src/strife/d_net.c10
-rw-r--r--src/strife/f_finale.c2
-rw-r--r--src/strife/g_game.c183
-rw-r--r--src/strife/hu_stuff.c14
-rw-r--r--src/strife/m_menu.c4
-rw-r--r--src/strife/p_saveg.c24
-rw-r--r--src/strife/p_saveg.h1
-rw-r--r--src/strife/p_setup.c100
-rw-r--r--src/strife/r_draw.c111
-rw-r--r--src/strife/st_stuff.c4
-rw-r--r--src/strife/wi_stuff.c47
-rw-r--r--src/w_main.c206
-rw-r--r--src/w_main.h32
-rw-r--r--src/z_zone.c3
107 files changed, 7211 insertions, 1570 deletions
diff --git a/src/.gitignore b/src/.gitignore
index 973a0073..aa8a4c05 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -3,7 +3,11 @@ Makefile.in
.deps
*.rc
chocolate-doom
+chocolate-heretic
+chocolate-hexen
chocolate-server
+chocolate-setup
*.exe
+*.desktop
tags
TAGS
diff --git a/src/Makefile.am b/src/Makefile.am
index 51baa567..2ba6dbef 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,6 +11,7 @@ games_PROGRAMS = @PROGRAM_PREFIX@doom \
@PROGRAM_PREFIX@setup
AM_CFLAGS = -I$(top_builddir)/textscreen \
+ -I$(top_builddir)/opl \
-I$(top_builddir)/pcsound \
@SDLMIXER_CFLAGS@ @SDLNET_CFLAGS@
@@ -72,6 +73,7 @@ tables.c tables.h \
v_video.c v_video.h \
v_patch.h \
w_checksum.c w_checksum.h \
+w_main.c w_main.h \
w_wad.c w_wad.h \
w_file.c w_file.h \
w_file_stdc.c \
@@ -115,6 +117,8 @@ FEATURE_SOUND_SOURCE_FILES = \
i_pcsound.c \
i_sdlsound.c \
i_sdlmusic.c \
+i_oplmusic.c \
+midifile.c midifile.h \
mus2mid.c mus2mid.h
# Some games support dehacked patches, some don't:
@@ -131,10 +135,11 @@ EXTRA_LIBS = \
$(top_builddir)/wince/libc_wince.a \
$(top_builddir)/textscreen/libtextscreen.a \
$(top_builddir)/pcsound/libpcsound.a \
+ $(top_builddir)/opl/libopl.a \
@LDFLAGS@ \
@SDL_LIBS@ \
@SDLMIXER_LIBS@ \
- @SDLNET_LIBS@
+ @SDLNET_LIBS@
if HAVE_WINDRES
@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc
@@ -145,9 +150,9 @@ endif
@PROGRAM_PREFIX@doom_LDADD = doom/libdoom.a $(EXTRA_LIBS)
if HAVE_WINDRES
-@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES) resource.rc
+@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc
else
-@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES)
+@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH)
endif
@PROGRAM_PREFIX@heretic_LDADD = heretic/libheretic.a $(EXTRA_LIBS)
@@ -204,3 +209,6 @@ icon.c : $(top_builddir)/data/doom8.ico
endif
+midiread : midifile.c
+ $(CC) -DTEST $(CFLAGS) @LDFLAGS@ $^ -o $@
+
diff --git a/src/deh_main.c b/src/deh_main.c
index 3f0a6f29..75934087 100644
--- a/src/deh_main.c
+++ b/src/deh_main.c
@@ -39,6 +39,8 @@
extern deh_section_t *deh_section_types[];
extern char *deh_signatures[];
+static boolean deh_initialized = false;
+
// If true, we can do long string replacements.
boolean deh_allow_long_strings = false;
@@ -322,6 +324,12 @@ int DEH_LoadFile(char *filename)
{
deh_context_t *context;
+ if (!deh_initialized)
+ {
+ InitializeSections();
+ deh_initialized = true;
+ }
+
printf(" loading %s\n", filename);
context = DEH_OpenFile(filename);
@@ -346,8 +354,6 @@ void DEH_Init(void)
char *filename;
int p;
- InitializeSections();
-
//!
// @category mod
//
diff --git a/src/deh_mapping.c b/src/deh_mapping.c
index b215b128..f061c298 100644
--- a/src/deh_mapping.c
+++ b/src/deh_mapping.c
@@ -34,12 +34,9 @@
#include "i_system.h"
#include "deh_mapping.h"
-//
-// Set the value of a particular field in a structure by name
-//
-
-boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
- void *structptr, char *name, int value)
+static deh_mapping_entry_t *GetMappingEntryByName(deh_context_t *context,
+ deh_mapping_t *mapping,
+ char *name)
{
int i;
@@ -49,44 +46,121 @@ boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
if (!strcasecmp(entry->name, name))
{
- void *location;
-
if (entry->location == NULL)
{
DEH_Warning(context, "Field '%s' is unsupported", name);
- return false;
+ return NULL;
}
- location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base);
-
- // printf("Setting %p::%s to %i (%i bytes)\n",
- // structptr, name, value, entry->size);
-
- switch (entry->size)
- {
- case 1:
- * ((uint8_t *) location) = value;
- break;
- case 2:
- * ((uint16_t *) location) = value;
- break;
- case 4:
- * ((uint32_t *) location) = value;
- break;
- default:
- DEH_Error(context, "Unknown field type for '%s' (BUG)", name);
- return false;
- }
-
- return true;
+ return entry;
}
}
- // field with this name not found
+ // Not found.
DEH_Warning(context, "Field named '%s' not found", name);
- return false;
+ return NULL;
+}
+
+//
+// Get the location of the specified field in the specified structure.
+//
+
+static void *GetStructField(void *structptr,
+ deh_mapping_t *mapping,
+ deh_mapping_entry_t *entry)
+{
+ unsigned int offset;
+
+ offset = (uint8_t *)entry->location - (uint8_t *)mapping->base;
+
+ return (uint8_t *)structptr + offset;
+}
+
+//
+// Set the value of a particular field in a structure by name
+//
+
+boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
+ void *structptr, char *name, int value)
+{
+ deh_mapping_entry_t *entry;
+ void *location;
+
+ entry = GetMappingEntryByName(context, mapping, name);
+
+ if (entry == NULL)
+ {
+ return false;
+ }
+
+ // Sanity check:
+
+ if (entry->is_string)
+ {
+ DEH_Error(context, "Tried to set '%s' as integer (BUG)", name);
+ return false;
+ }
+
+ location = GetStructField(structptr, mapping, entry);
+
+ // printf("Setting %p::%s to %i (%i bytes)\n",
+ // structptr, name, value, entry->size);
+
+ // Set field content based on its type:
+
+ switch (entry->size)
+ {
+ case 1:
+ * ((uint8_t *) location) = value;
+ break;
+ case 2:
+ * ((uint16_t *) location) = value;
+ break;
+ case 4:
+ * ((uint32_t *) location) = value;
+ break;
+ default:
+ DEH_Error(context, "Unknown field type for '%s' (BUG)", name);
+ return false;
+ }
+
+ return true;
+}
+
+//
+// Set the value of a string field in a structure by name
+//
+
+boolean DEH_SetStringMapping(deh_context_t *context, deh_mapping_t *mapping,
+ void *structptr, char *name, char *value)
+{
+ deh_mapping_entry_t *entry;
+ void *location;
+
+ entry = GetMappingEntryByName(context, mapping, name);
+
+ if (entry == NULL)
+ {
+ return false;
+ }
+
+ // Sanity check:
+
+ if (!entry->is_string)
+ {
+ DEH_Error(context, "Tried to set '%s' as string (BUG)", name);
+ return false;
+ }
+
+ location = GetStructField(structptr, mapping, entry);
+
+ // Copy value into field:
+
+ strncpy(location, value, entry->size);
+
+ return true;
}
void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping,
diff --git a/src/deh_mapping.h b/src/deh_mapping.h
index 4862dec9..129ddcfd 100644
--- a/src/deh_mapping.h
+++ b/src/deh_mapping.h
@@ -42,17 +42,23 @@
#define DEH_MAPPING(deh_name, fieldname) \
{deh_name, &deh_mapping_base.fieldname, \
- sizeof(deh_mapping_base.fieldname)},
+ sizeof(deh_mapping_base.fieldname), \
+ false},
+
+#define DEH_MAPPING_STRING(deh_name, fieldname) \
+ {deh_name, &deh_mapping_base.fieldname, \
+ sizeof(deh_mapping_base.fieldname), \
+ true},
#define DEH_UNSUPPORTED_MAPPING(deh_name) \
- {deh_name, NULL, -1},
-
+ {deh_name, NULL, -1, false},
+
#define DEH_END_MAPPING \
{NULL, NULL, -1} \
} \
};
-
+
#define MAX_MAPPING_ENTRIES 32
@@ -73,6 +79,10 @@ struct deh_mapping_entry_s
// field size
int size;
+
+ // if true, this is a string value.
+
+ boolean is_string;
};
struct deh_mapping_s
@@ -81,8 +91,10 @@ struct deh_mapping_s
deh_mapping_entry_t entries[MAX_MAPPING_ENTRIES];
};
-boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
+boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping,
void *structptr, char *name, int value);
+boolean DEH_SetStringMapping(deh_context_t *context, deh_mapping_t *mapping,
+ void *structptr, char *name, char *value);
void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping,
void *structptr);
diff --git a/src/deh_str.c b/src/deh_str.c
index 0baaa7e8..9bd429b6 100644
--- a/src/deh_str.c
+++ b/src/deh_str.c
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
#include "doomtype.h"
#include "deh_str.h"
@@ -179,3 +180,229 @@ void DEH_AddStringReplacement(char *from_text, char *to_text)
DEH_AddToHashtable(sub);
}
+typedef enum
+{
+ FORMAT_ARG_INVALID,
+ FORMAT_ARG_INT,
+ FORMAT_ARG_FLOAT,
+ FORMAT_ARG_CHAR,
+ FORMAT_ARG_STRING,
+ FORMAT_ARG_PTR,
+ FORMAT_ARG_SAVE_POS
+} format_arg_t;
+
+// Get the type of a format argument.
+// We can mix-and-match different format arguments as long as they
+// are for the same data type.
+
+static format_arg_t FormatArgumentType(char c)
+{
+ switch (c)
+ {
+ case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
+ return FORMAT_ARG_INT;
+
+ case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
+ case 'a': case 'A':
+ return FORMAT_ARG_FLOAT;
+
+ case 'c': case 'C':
+ return FORMAT_ARG_CHAR;
+
+ case 's': case 'S':
+ return FORMAT_ARG_STRING;
+
+ case 'p':
+ return FORMAT_ARG_PTR;
+
+ case 'n':
+ return FORMAT_ARG_SAVE_POS;
+
+ default:
+ return FORMAT_ARG_INVALID;
+ }
+}
+
+// Given the specified string, get the type of the first format
+// string encountered.
+
+static format_arg_t NextFormatArgument(char **str)
+{
+ format_arg_t argtype;
+
+ // Search for the '%' starting the next string.
+
+ while (**str != '\0')
+ {
+ if (**str == '%')
+ {
+ ++*str;
+
+ // Don't stop for double-%s.
+
+ if (**str != '%')
+ {
+ break;
+ }
+ }
+
+ ++*str;
+ }
+
+ // Find the type of the format string.
+
+ while (**str != '\0')
+ {
+ argtype = FormatArgumentType(**str);
+
+ if (argtype != FORMAT_ARG_INVALID)
+ {
+ ++*str;
+
+ return argtype;
+ }
+
+ ++*str;
+ }
+
+ // Stop searching, we have reached the end.
+
+ *str = NULL;
+
+ return FORMAT_ARG_INVALID;
+}
+
+// Check if the specified argument type is a valid replacement for
+// the original.
+
+static boolean ValidArgumentReplacement(format_arg_t original,
+ format_arg_t replacement)
+{
+ // In general, the original and replacement types should be
+ // identical. However, there are some cases where the replacement
+ // is valid and the types don't match.
+
+ // Characters can be represented as ints.
+
+ if (original == FORMAT_ARG_CHAR && replacement == FORMAT_ARG_INT)
+ {
+ return true;
+ }
+
+ // Strings are pointers.
+
+ if (original == FORMAT_ARG_STRING && replacement == FORMAT_ARG_PTR)
+ {
+ return true;
+ }
+
+ return original == replacement;
+}
+
+// Return true if the specified string contains no format arguments.
+
+static boolean ValidFormatReplacement(char *original, char *replacement)
+{
+ char *rover1;
+ char *rover2;
+ int argtype1, argtype2;
+
+ // Check each argument in turn and compare types.
+
+ rover1 = original; rover2 = replacement;
+
+ for (;;)
+ {
+ argtype1 = NextFormatArgument(&rover1);
+ argtype2 = NextFormatArgument(&rover2);
+
+ if (argtype2 == FORMAT_ARG_INVALID)
+ {
+ // No more arguments left to read from the replacement string.
+
+ break;
+ }
+ else if (argtype1 == FORMAT_ARG_INVALID)
+ {
+ // Replacement string has more arguments than the original.
+
+ return false;
+ }
+ else if (!ValidArgumentReplacement(argtype1, argtype2))
+ {
+ // Not a valid replacement argument.
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Get replacement format string, checking arguments.
+
+static char *FormatStringReplacement(char *s)
+{
+ char *repl;
+
+ repl = DEH_String(s);
+
+ if (!ValidFormatReplacement(s, repl))
+ {
+ printf("WARNING: Unsafe dehacked replacement provided for "
+ "printf format string: %s\n", s);
+
+ return s;
+ }
+
+ return repl;
+}
+
+// printf(), performing a replacement on the format string.
+
+void DEH_printf(char *fmt, ...)
+{
+ va_list args;
+ char *repl;
+
+ repl = FormatStringReplacement(fmt);
+
+ va_start(args, fmt);
+
+ vprintf(repl, args);
+
+ va_end(args);
+}
+
+// fprintf(), performing a replacement on the format string.
+
+void DEH_fprintf(FILE *fstream, char *fmt, ...)
+{
+ va_list args;
+ char *repl;
+
+ repl = FormatStringReplacement(fmt);
+
+ va_start(args, fmt);
+
+ vfprintf(fstream, repl, args);
+
+ va_end(args);
+}
+
+// snprintf(), performing a replacement on the format string.
+
+void DEH_snprintf(char *buffer, size_t len, char *fmt, ...)
+{
+ va_list args;
+ char *repl;
+
+ repl = FormatStringReplacement(fmt);
+
+ va_start(args, fmt);
+
+ vsnprintf(buffer, len, repl, args);
+
+ va_end(args);
+}
+
diff --git a/src/deh_str.h b/src/deh_str.h
index 986536de..06bcb420 100644
--- a/src/deh_str.h
+++ b/src/deh_str.h
@@ -27,6 +27,8 @@
#ifndef DEH_STR_H
#define DEH_STR_H
+#include <stdio.h>
+
#include "doomfeatures.h"
// Used to do dehacked text substitutions throughout the program
@@ -34,11 +36,18 @@
#ifdef FEATURE_DEHACKED
char *DEH_String(char *s);
+void DEH_printf(char *fmt, ...);
+void DEH_fprintf(FILE *fstream, char *fmt, ...);
+void DEH_snprintf(char *buffer, size_t len, char *fmt, ...);
void DEH_AddStringReplacement(char *from_text, char *to_text);
+
#else
#define DEH_String(x) (x)
+#define DEH_printf printf
+#define DEH_fprintf fprintf
+#define DEH_snprintf snprintf
#endif
diff --git a/src/doom/.gitignore b/src/doom/.gitignore
index 973a0073..d4e88e5a 100644
--- a/src/doom/.gitignore
+++ b/src/doom/.gitignore
@@ -1,9 +1,5 @@
Makefile
Makefile.in
.deps
-*.rc
-chocolate-doom
-chocolate-server
-*.exe
tags
TAGS
diff --git a/src/doom/am_map.c b/src/doom/am_map.c
index 89a5dffc..d957ea67 100644
--- a/src/doom/am_map.c
+++ b/src/doom/am_map.c
@@ -500,7 +500,7 @@ void AM_loadPics(void)
for (i=0;i<10;i++)
{
- sprintf(namebuf, DEH_String("AMMNUM%d"), i);
+ DEH_snprintf(namebuf, 9, "AMMNUM%d", i);
marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
}
@@ -513,7 +513,7 @@ void AM_unloadPics(void)
for (i=0;i<10;i++)
{
- sprintf(namebuf, DEH_String("AMMNUM%d"), i);
+ DEH_snprintf(namebuf, 9, "AMMNUM%d", i);
W_ReleaseLumpName(namebuf);
}
}
@@ -1020,7 +1020,7 @@ AM_drawFline
|| fl->b.x < 0 || fl->b.x >= f_w
|| fl->b.y < 0 || fl->b.y >= f_h)
{
- fprintf(stderr, DEH_String("fuck %d \r"), fuck++);
+ DEH_fprintf(stderr, "fuck %d \r", fuck++);
return;
}
diff --git a/src/doom/d_main.c b/src/doom/d_main.c
index 4e7812cc..f3a4b037 100644
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -45,8 +45,8 @@
#include "d_iwad.h"
#include "z_zone.h"
+#include "w_main.h"
#include "w_wad.h"
-#include "w_merge.h"
#include "s_sound.h"
#include "v_video.h"
@@ -358,6 +358,12 @@ void D_BindVariables(void)
M_BindWeaponControls();
M_BindMapControls();
M_BindMenuControls();
+ 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();
@@ -827,7 +833,6 @@ static boolean CheckChex(char *iwadname)
// print title for every printed line
char title[128];
-
static boolean D_AddFile(char *filename)
{
wad_file_t *handle;
@@ -1069,7 +1074,7 @@ void D_DoomMain (void)
I_PrintBanner(PACKAGE_STRING);
- printf (DEH_String("Z_Init: Init zone memory allocation daemon. \n"));
+ DEH_printf("Z_Init: Init zone memory allocation daemon. \n");
Z_Init ();
#ifdef FEATURE_MULTIPLAYER
@@ -1188,7 +1193,7 @@ void D_DoomMain (void)
deathmatch = 2;
if (devparm)
- printf(DEH_String(D_DEVSTR));
+ DEH_printf(D_DEVSTR);
// find which dir to use for config files
@@ -1236,7 +1241,7 @@ void D_DoomMain (void)
scale = 10;
if (scale > 400)
scale = 400;
- printf (DEH_String("turbo scale: %i%%\n"),scale);
+ 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;
@@ -1244,11 +1249,11 @@ void D_DoomMain (void)
}
// init subsystems
- printf(DEH_String("V_Init: allocate screens.\n"));
- V_Init();
+ DEH_printf("V_Init: allocate screens.\n");
+ V_Init ();
// Load configuration files before initialising other subsystems.
- printf(DEH_String("M_LoadDefaults: Load system defaults.\n"));
+ DEH_printf("M_LoadDefaults: Load system defaults.\n");
M_SetConfigFilenames("default.cfg", PROGRAM_PREFIX "doom.cfg");
D_BindVariables();
M_LoadDefaults();
@@ -1256,160 +1261,9 @@ void D_DoomMain (void)
// Save configuration at exit.
I_AtExit(M_SaveDefaults, false);
- printf (DEH_String("W_Init: Init WADfiles.\n"));
+ DEH_printf("W_Init: Init WADfiles.\n");
D_AddFile(iwadfile);
-
-#ifdef FEATURE_WAD_MERGE
-
- // Merged PWADs are loaded first, because they are supposed to be
- // modified IWADs.
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of deutex's -merge option, merging a PWAD
- // into the main IWAD. Multiple files may be specified.
- //
-
- p = M_CheckParm("-merge");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging %s\n", filename);
- W_MergeFile(filename);
- }
- }
-
- // NWT-style merging:
-
- // NWT's -merge option:
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of NWT's -merge option. Multiple files
- // may be specified.
-
- p = M_CheckParm("-nwtmerge");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" performing NWT-style merge of %s\n", filename);
- W_NWTDashMerge(filename);
- }
- }
-
- // Add flats
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of NWT's -af option, merging flats into
- // the main IWAD directory. Multiple files may be specified.
- //
-
- p = M_CheckParm("-af");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging flats from %s\n", filename);
- W_NWTMergeFile(filename, W_NWT_MERGE_FLATS);
- }
- }
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of NWT's -as option, merging sprites
- // into the main IWAD directory. Multiple files may be specified.
- //
-
- p = M_CheckParm("-as");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging sprites from %s\n", filename);
- W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES);
- }
- }
-
- //!
- // @arg <files>
- // @category mod
- //
- // Equivalent to "-af <files> -as <files>".
- //
-
- p = M_CheckParm("-aa");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging sprites and flats from %s\n", filename);
- W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES | W_NWT_MERGE_FLATS);
- }
- }
-
-#endif
-
- //!
- // @arg <files>
- // @vanilla
- //
- // Load the specified PWAD files.
- //
-
- p = M_CheckParm ("-file");
- if (p)
- {
- // the parms after p are wadfile/lump names,
- // until end of parms or another - preceded parm
- modifiedgame = true; // homebrew levels
- while (++p != myargc && myargv[p][0] != '-')
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- D_AddFile(filename);
- }
- }
-
- // Debug:
-// W_PrintDirectory();
+ modifiedgame = W_ParseCommandLine();
// add any files specified on the command line with -file wadfile
// to the wad list
@@ -1603,8 +1457,8 @@ void D_DoomMain (void)
if (p && p < myargc-1 && deathmatch)
{
- printf(DEH_String("Austin Virtual Gaming: Levels will end "
- "after 20 minutes\n"));
+ DEH_printf("Austin Virtual Gaming: Levels will end "
+ "after 20 minutes\n");
timelimit = 20;
}
@@ -1686,16 +1540,16 @@ void D_DoomMain (void)
I_PrintStartupBanner(gamedescription);
PrintDehackedBanners();
- printf (DEH_String("M_Init: Init miscellaneous info.\n"));
+ DEH_printf("M_Init: Init miscellaneous info.\n");
M_Init ();
- printf (DEH_String("R_Init: Init DOOM refresh daemon - "));
+ DEH_printf("R_Init: Init DOOM refresh daemon - ");
R_Init ();
- printf (DEH_String("\nP_Init: Init Playloop state.\n"));
+ DEH_printf("\nP_Init: Init Playloop state.\n");
P_Init ();
- printf (DEH_String("I_Init: Setting up machine state.\n"));
+ DEH_printf("I_Init: Setting up machine state.\n");
I_CheckIsScreensaver();
I_InitTimer();
I_InitJoystick();
@@ -1705,18 +1559,18 @@ void D_DoomMain (void)
NET_Init ();
#endif
- printf (DEH_String("S_Init: Setting up sound.\n"));
+ DEH_printf("S_Init: Setting up sound.\n");
S_Init (sfxVolume * 8, musicVolume * 8);
- printf (DEH_String("D_CheckNetGame: Checking network game status.\n"));
+ DEH_printf("D_CheckNetGame: Checking network game status.\n");
D_CheckNetGame ();
PrintGameVersion();
- printf (DEH_String("HU_Init: Setting up heads up display.\n"));
+ DEH_printf("HU_Init: Setting up heads up display.\n");
HU_Init ();
- printf (DEH_String("ST_Init: Init status bar.\n"));
+ DEH_printf("ST_Init: Init status bar.\n");
ST_Init ();
// If Doom II without a MAP01 lump, this is a store demo.
diff --git a/src/doom/d_net.c b/src/doom/d_net.c
index e30ead83..464922d4 100644
--- a/src/doom/d_net.c
+++ b/src/doom/d_net.c
@@ -374,17 +374,17 @@ void D_CheckNetGame (void)
++num_players;
}
- printf (DEH_String("startskill %i deathmatch: %i startmap: %i startepisode: %i\n"),
- startskill, deathmatch, startmap, startepisode);
+ DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
+ startskill, deathmatch, startmap, startepisode);
- printf(DEH_String("player %i of %i (%i nodes)\n"),
- consoleplayer+1, num_players, num_players);
+ 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)
{
- printf(DEH_String("Levels will end after %d minute"),timelimit);
+ DEH_printf("Levels will end after %d minute", timelimit);
if (timelimit > 1)
printf("s");
printf(".\n");
diff --git a/src/doom/f_finale.c b/src/doom/f_finale.c
index ece82b43..dfbeafbe 100644
--- a/src/doom/f_finale.c
+++ b/src/doom/f_finale.c
@@ -663,7 +663,7 @@ void F_BunnyScroll (void)
laststage = stage;
}
- sprintf (name, DEH_String("END%i"), stage);
+ DEH_snprintf(name, 10, "END%i", stage);
V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
(SCREENHEIGHT - 8 * 8) / 2,
W_CacheLumpName (name,PU_CACHE));
diff --git a/src/doom/g_game.c b/src/doom/g_game.c
index 8d0e4503..ad7155a0 100644
--- a/src/doom/g_game.c
+++ b/src/doom/g_game.c
@@ -176,14 +176,37 @@ static int *weapon_keys[] = {
&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.
+
+static const struct
+{
+ weapontype_t weapon;
+ weapontype_t weapon_num;
+} weapon_order_table[] = {
+ { wp_fist, wp_fist },
+ { wp_chainsaw, wp_fist },
+ { wp_pistol, wp_pistol },
+ { wp_shotgun, wp_shotgun },
+ { wp_supershotgun, wp_shotgun },
+ { wp_chaingun, wp_chaingun },
+ { wp_missile, wp_missile },
+ { wp_plasma, wp_plasma },
+ { wp_bfg, wp_bfg }
+};
+
#define SLOWTURNTICS 6
#define NUMKEYS 256
+#define MAX_JOY_BUTTONS 20
static boolean gamekeydown[NUMKEYS];
static int turnheld; // for accelerative turning
-static boolean mousearray[4];
+static boolean mousearray[MAX_MOUSE_BUTTONS + 1];
static boolean *mousebuttons = &mousearray[1]; // allow [-1]
// mouse values are used once
@@ -197,8 +220,6 @@ static int dclicktime2;
static boolean dclickstate2;
static int dclicks2;
-#define MAX_JOY_BUTTONS 20
-
// joystick values are repeated
static int joyxmove;
static int joyymove;
@@ -337,7 +358,63 @@ int G_CmdChecksum (ticcmd_t* cmd)
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;
+ }
+
+ // Can't select the fist if we have the chainsaw, unless
+ // we also have the berserk pack.
+
+ if (weapon == wp_fist
+ && players[consoleplayer].weaponowned[wp_chainsaw]
+ && !players[consoleplayer].powers[pw_strength])
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static int G_NextWeapon(int direction)
+{
+ weapontype_t weapon;
+ int i;
+
+ // Find index in the table.
+
+ if (players[consoleplayer].pendingweapon == wp_nochange)
+ {
+ weapon = players[consoleplayer].readyweapon;
+ }
+ else
+ {
+ weapon = players[consoleplayer].pendingweapon;
+ }
+
+ for (i=0; i<arrlen(weapon_order_table); ++i)
+ {
+ if (weapon_order_table[i].weapon == weapon)
+ {
+ break;
+ }
+ }
+
+ // Switch weapon.
+
+ do
+ {
+ i += direction;
+ i = (i + arrlen(weapon_order_table)) % arrlen(weapon_order_table);
+ } while (!WeaponSelectable(weapon_order_table[i].weapon));
+
+ return weapon_order_table[i].weapon_num;
+}
//
// G_BuildTiccmd
@@ -465,20 +542,34 @@ void G_BuildTiccmd (ticcmd_t* cmd)
dclicks = 0;
}
- // chainsaw overrides
+ // 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.
- for (i=0; i<arrlen(weapon_keys); ++i)
+ if (next_weapon != 0)
+ {
+ i = G_NextWeapon(next_weapon);
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i << BT_WEAPONSHIFT;
+ next_weapon = 0;
+ }
+ else
{
- int key = *weapon_keys[i];
+ // Check weapon keys.
- if (gamekeydown[key])
+ for (i=0; i<arrlen(weapon_keys); ++i)
{
- cmd->buttons |= BT_CHANGE;
- cmd->buttons |= i<<BT_WEAPONSHIFT;
- break;
+ int key = *weapon_keys[i];
+
+ if (gamekeydown[key])
+ {
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i<<BT_WEAPONSHIFT;
+ break;
+ }
}
}
-
+
// mouse
if (mousebuttons[mousebforward])
{
@@ -657,7 +748,6 @@ void G_DoLoadLevel (void)
players[consoleplayer].message = "Press escape to quit.";
}
}
-
static void SetJoyButtons(unsigned int buttons_mask)
{
@@ -665,10 +755,54 @@ static void SetJoyButtons(unsigned int buttons_mask)
for (i=0; i<MAX_JOY_BUTTONS; ++i)
{
- joybuttons[i] = (buttons_mask & (1 << i)) != 0;
+ 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.
@@ -677,7 +811,7 @@ 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_F12 && (singledemo || !deathmatch) )
+ && ev->data1 == key_spy && (singledemo || !deathmatch) )
{
// spy mode
do
@@ -737,6 +871,18 @@ boolean G_Responder (event_t* ev)
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:
@@ -757,9 +903,7 @@ boolean G_Responder (event_t* ev)
return false; // always let key up events filter down
case ev_mouse:
- mousebuttons[0] = ev->data1 & 1;
- mousebuttons[1] = ev->data1 & 2;
- mousebuttons[2] = ev->data1 & 4;
+ SetMouseButtons(ev->data1);
mousex = ev->data2*(mouseSensitivity+5)/10;
mousey = ev->data3*(mouseSensitivity+5)/10;
return true; // eat events
@@ -1428,6 +1572,8 @@ void G_DoLoadGame (void)
return;
}
+ savegame_error = false;
+
if (!P_ReadSaveGameHeader())
{
fclose(save_stream);
@@ -1495,6 +1641,8 @@ void G_DoSaveGame (void)
return;
}
+ savegame_error = false;
+
P_WriteSaveGameHeader(savedescription);
P_ArchivePlayers ();
@@ -1780,7 +1928,7 @@ void G_WriteDemoTiccmd (ticcmd_t* cmd)
{
byte *demo_start;
- if (gamekeydown['q']) // press q to end demo recording
+ if (gamekeydown[key_demo_quit]) // press q to end demo recording
G_CheckDemoStatus ();
demo_start = demo_p;
diff --git a/src/doom/hu_stuff.c b/src/doom/hu_stuff.c
index ca74ce92..f9271b3d 100644
--- a/src/doom/hu_stuff.c
+++ b/src/doom/hu_stuff.c
@@ -302,7 +302,7 @@ void HU_Init(void)
j = HU_FONTSTART;
for (i=0;i<HU_FONTSIZE;i++)
{
- sprintf(buffer, DEH_String("STCFN%.3d"), j++);
+ DEH_snprintf(buffer, 9, "STCFN%.3d", j++);
hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
}
@@ -529,14 +529,6 @@ boolean HU_Responder(event_t *ev)
int i;
int numplayers;
- static char destination_keys[MAXPLAYERS] =
- {
- HUSTR_KEYGREEN,
- HUSTR_KEYINDIGO,
- HUSTR_KEYBROWN,
- HUSTR_KEYRED
- };
-
static int num_nobrainers = 0;
numplayers = 0;
@@ -565,7 +557,7 @@ boolean HU_Responder(event_t *ev)
message_counter = HU_MSGTIMEOUT;
eatkey = true;
}
- else if (netgame && ev->data2 == HU_INPUTTOGGLE)
+ else if (netgame && ev->data2 == key_multi_msg)
{
eatkey = chat_on = true;
HUlib_resetIText(&w_chat);
@@ -575,7 +567,7 @@ boolean HU_Responder(event_t *ev)
{
for (i=0; i<MAXPLAYERS ; i++)
{
- if (ev->data2 == destination_keys[i])
+ if (ev->data2 == key_multi_msgplayer[i])
{
if (playeringame[i] && i!=consoleplayer)
{
diff --git a/src/doom/m_menu.c b/src/doom/m_menu.c
index a0d66dd4..a6f7bbfb 100644
--- a/src/doom/m_menu.c
+++ b/src/doom/m_menu.c
@@ -707,7 +707,7 @@ void M_QuickSave(void)
quickSaveSlot = -2; // means to pick a slot now
return;
}
- sprintf(tempstring,DEH_String(QSPROMPT),savegamestrings[quickSaveSlot]);
+ DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]);
M_StartMessage(tempstring,M_QuickSaveResponse,true);
}
@@ -739,7 +739,7 @@ void M_QuickLoad(void)
M_StartMessage(DEH_String(QSAVESPOT),NULL,false);
return;
}
- sprintf(tempstring,DEH_String(QLPROMPT),savegamestrings[quickSaveSlot]);
+ DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]);
M_StartMessage(tempstring,M_QuickLoadResponse,true);
}
diff --git a/src/doom/p_saveg.c b/src/doom/p_saveg.c
index e557e494..968120c0 100644
--- a/src/doom/p_saveg.c
+++ b/src/doom/p_saveg.c
@@ -44,6 +44,7 @@
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
@@ -75,7 +76,7 @@ char *P_SaveGameFile(int slot)
filename = malloc(strlen(savegamedir) + 32);
}
- sprintf(basename, DEH_String(SAVEGAMENAME "%d.dsg"), slot);
+ DEH_snprintf(basename, 32, SAVEGAMENAME "%d.dsg", slot);
sprintf(filename, "%s%s", savegamedir, basename);
@@ -88,14 +89,31 @@ static byte saveg_read8(void)
{
byte result;
- fread(&result, 1, 1, save_stream);
+ 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)
{
- fwrite(&value, 1, 1, save_stream);
+ 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)
diff --git a/src/doom/p_saveg.h b/src/doom/p_saveg.h
index 3a96cc3e..5488289c 100644
--- a/src/doom/p_saveg.h
+++ b/src/doom/p_saveg.h
@@ -64,6 +64,7 @@ void P_ArchiveSpecials (void);
void P_UnArchiveSpecials (void);
extern FILE *save_stream;
+extern boolean savegame_error;
#endif
diff --git a/src/doom/p_setup.c b/src/doom/p_setup.c
index 2a3a8f85..7d9d4318 100644
--- a/src/doom/p_setup.c
+++ b/src/doom/p_setup.c
@@ -33,6 +33,7 @@
#include "deh_main.h"
#include "i_swap.h"
+#include "m_argv.h"
#include "m_bbox.h"
#include "g_game.h"
@@ -76,6 +77,7 @@ line_t* lines;
int numsides;
side_t* sides;
+static int totallines;
// BLOCKMAP
// Created from axis aligned bounding box
@@ -534,7 +536,6 @@ void P_GroupLines (void)
line_t** linebuffer;
int i;
int j;
- int total;
line_t* li;
sector_t* sector;
subsector_t* ss;
@@ -552,21 +553,21 @@ void P_GroupLines (void)
// count number of lines in each sector
li = lines;
- total = 0;
+ totallines = 0;
for (i=0 ; i<numlines ; i++, li++)
{
- total++;
+ totallines++;
li->frontsector->linecount++;
if (li->backsector && li->backsector != li->frontsector)
{
li->backsector->linecount++;
- total++;
+ totallines++;
}
}
// build line tables for each sector
- linebuffer = Z_Malloc (total*sizeof(line_t *), PU_LEVEL, 0);
+ linebuffer = Z_Malloc (totallines*sizeof(line_t *), PU_LEVEL, 0);
for (i=0; i<numsectors; ++i)
{
@@ -643,6 +644,87 @@ void P_GroupLines (void)
}
+// 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
@@ -692,9 +774,9 @@ P_SetupLevel
if ( gamemode == commercial)
{
if (map<10)
- sprintf (lumpname, DEH_String("map0%i"), map);
+ DEH_snprintf(lumpname, 9, "map0%i", map);
else
- sprintf (lumpname, DEH_String("map%i"), map);
+ DEH_snprintf(lumpname, 9, "map%i", map);
}
else
{
@@ -719,9 +801,9 @@ P_SetupLevel
P_LoadSubsectors (lumpnum+ML_SSECTORS);
P_LoadNodes (lumpnum+ML_NODES);
P_LoadSegs (lumpnum+ML_SEGS);
-
- rejectmatrix = W_CacheLumpNum (lumpnum+ML_REJECT,PU_LEVEL);
+
P_GroupLines ();
+ P_LoadReject (lumpnum+ML_REJECT);
bodyqueslot = 0;
deathmatch_p = deathmatchstarts;
diff --git a/src/doom/r_draw.c b/src/doom/r_draw.c
index 1b6420d9..80362208 100644
--- a/src/doom/r_draw.c
+++ b/src/doom/r_draw.c
@@ -597,48 +597,54 @@ int dscount;
// Draws the actual span.
void R_DrawSpan (void)
{
- fixed_t xfrac;
- fixed_t yfrac;
- byte* dest;
- int count;
- int spot;
-
-#ifdef RANGECHECK
+ 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
+ || ds_x2>=SCREENWIDTH
|| (unsigned)ds_y>SCREENHEIGHT)
{
I_Error( "R_DrawSpan: %i to %i at %i",
ds_x1,ds_x2,ds_y);
}
-// dscount++;
-#endif
+// 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);
-
- xfrac = ds_xfrac;
- yfrac = ds_yfrac;
-
dest = ylookup[ds_y] + columnofs[ds_x1];
// We do not check for zero spans here?
- count = ds_x2 - ds_x1;
+ count = ds_x2 - ds_x1;
- do
+ do
{
- // Current texture index in u,v.
- spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
+ // 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]];
- // Next step in u,v.
- xfrac += ds_xstep;
- yfrac += ds_ystep;
-
- } while (count--);
-}
+ position += step;
+
+ } while (count--);
+}
@@ -718,49 +724,54 @@ void R_DrawSpan (void)
//
// Again..
//
-void R_DrawSpanLow (void)
-{
- fixed_t xfrac;
- fixed_t yfrac;
- byte* dest;
- int count;
- int spot;
-
-#ifdef RANGECHECK
+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
+ || ds_x2>=SCREENWIDTH
|| (unsigned)ds_y>SCREENHEIGHT)
{
I_Error( "R_DrawSpan: %i to %i at %i",
ds_x1,ds_x2,ds_y);
}
// dscount++;
-#endif
-
- xfrac = ds_xfrac;
- yfrac = ds_yfrac;
-
- count = (ds_x2 - ds_x1);
+#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
- {
- spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
+
+ 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]];
-
- xfrac += ds_xstep;
- yfrac += ds_ystep;
+ *dest++ = ds_colormap[ds_source[spot]];
- } while (count--);
+ position += step;
+
+ } while (count--);
}
//
diff --git a/src/doom/s_sound.c b/src/doom/s_sound.c
index f829956c..7f4411dd 100644
--- a/src/doom/s_sound.c
+++ b/src/doom/s_sound.c
@@ -618,6 +618,15 @@ void S_ChangeMusic(int musicnum, int looping)
char namebuf[9];
void *handle;
+ // The Doom IWAD file has two versions of the intro music: d_intro
+ // and d_introa. The latter is used for OPL playback.
+
+ if (musicnum == mus_intro && (snd_musicdevice == SNDDEVICE_ADLIB
+ || snd_musicdevice == SNDDEVICE_SB))
+ {
+ musicnum = mus_introa;
+ }
+
if (musicnum <= mus_None || musicnum >= NUMMUSIC)
{
I_Error("Bad music number %d", musicnum);
diff --git a/src/doom/st_stuff.c b/src/doom/st_stuff.c
index 160244ce..7e5e225c 100644
--- a/src/doom/st_stuff.c
+++ b/src/doom/st_stuff.c
@@ -1085,10 +1085,10 @@ static void ST_loadUnloadGraphics(load_callback_t callback)
// Load the numbers, tall and short
for (i=0;i<10;i++)
{
- sprintf(namebuf, DEH_String("STTNUM%d"), i);
+ DEH_snprintf(namebuf, 9, "STTNUM%d", i);
callback(namebuf, &tallnum[i]);
- sprintf(namebuf, DEH_String("STYSNUM%d"), i);
+ DEH_snprintf(namebuf, 9, "STYSNUM%d", i);
callback(namebuf, &shortnum[i]);
}
@@ -1100,7 +1100,7 @@ static void ST_loadUnloadGraphics(load_callback_t callback)
// key cards
for (i=0;i<NUMCARDS;i++)
{
- sprintf(namebuf, DEH_String("STKEYS%d"), i);
+ DEH_snprintf(namebuf, 9, "STKEYS%d", i);
callback(namebuf, &keys[i]);
}
@@ -1110,7 +1110,7 @@ static void ST_loadUnloadGraphics(load_callback_t callback)
// arms ownership widgets
for (i=0; i<6; i++)
{
- sprintf(namebuf, DEH_String("STGNUM%d"), i+2);
+ DEH_snprintf(namebuf, 9, "STGNUM%d", i+2);
// gray #
callback(namebuf, &arms[i][0]);
@@ -1120,7 +1120,7 @@ static void ST_loadUnloadGraphics(load_callback_t callback)
}
// face backgrounds for different color players
- sprintf(namebuf, DEH_String("STFB%d"), consoleplayer);
+ DEH_snprintf(namebuf, 9, "STFB%d", consoleplayer);
callback(namebuf, &faceback);
// status bar background bits
@@ -1132,23 +1132,23 @@ static void ST_loadUnloadGraphics(load_callback_t callback)
{
for (j=0; j<ST_NUMSTRAIGHTFACES; j++)
{
- sprintf(namebuf, DEH_String("STFST%d%d"), i, j);
+ DEH_snprintf(namebuf, 9, "STFST%d%d", i, j);
callback(namebuf, &faces[facenum]);
++facenum;
}
- sprintf(namebuf, DEH_String("STFTR%d0"), i); // turn right
+ DEH_snprintf(namebuf, 9, "STFTR%d0", i); // turn right
callback(namebuf, &faces[facenum]);
++facenum;
- sprintf(namebuf, DEH_String("STFTL%d0"), i); // turn left
+ DEH_snprintf(namebuf, 9, "STFTL%d0", i); // turn left
callback(namebuf, &faces[facenum]);
++facenum;
- sprintf(namebuf, DEH_String("STFOUCH%d"), i); // ouch!
+ DEH_snprintf(namebuf, 9, "STFOUCH%d", i); // ouch!
callback(namebuf, &faces[facenum]);
++facenum;
- sprintf(namebuf, DEH_String("STFEVL%d"), i); // evil grin ;)
+ DEH_snprintf(namebuf, 9, "STFEVL%d", i); // evil grin ;)
callback(namebuf, &faces[facenum]);
++facenum;
- sprintf(namebuf, DEH_String("STFKILL%d"), i); // pissed off
+ DEH_snprintf(namebuf, 9, "STFKILL%d", i); // pissed off
callback(namebuf, &faces[facenum]);
++facenum;
}
diff --git a/src/doom/wi_stuff.c b/src/doom/wi_stuff.c
index 83f5052f..45c09343 100644
--- a/src/doom/wi_stuff.c
+++ b/src/doom/wi_stuff.c
@@ -1571,16 +1571,16 @@ static void WI_loadUnloadData(load_callback_t callback)
if (gamemode == commercial)
{
for (i=0 ; i<NUMCMAPS ; i++)
- {
- sprintf(name, DEH_String("CWILV%2.2d"), i);
+ {
+ DEH_snprintf(name, 9, "CWILV%2.2d", i);
callback(name, &lnames[i]);
- }
+ }
}
else
{
for (i=0 ; i<NUMMAPS ; i++)
{
- sprintf(name, DEH_String("WILV%d%d"), wbs->epsd, i);
+ DEH_snprintf(name, 9, "WILV%d%d", wbs->epsd, i);
callback(name, &lnames[i]);
}
@@ -1592,7 +1592,7 @@ static void WI_loadUnloadData(load_callback_t callback)
// splat
callback(DEH_String("WISPLAT"), &splat[0]);
-
+
if (wbs->epsd < 3)
{
for (j=0;j<NUMANIMS[wbs->epsd];j++)
@@ -1601,17 +1601,16 @@ static void WI_loadUnloadData(load_callback_t callback)
for (i=0;i<a->nanims;i++)
{
// MONDO HACK!
- if (wbs->epsd != 1 || j != 8)
+ if (wbs->epsd != 1 || j != 8)
{
// animations
- sprintf(name, DEH_String("WIA%d%.2d%.2d"),
- wbs->epsd, j, i);
+ 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];
+ a->p[i] = anims[1][4].p[i];
}
}
}
@@ -1624,7 +1623,7 @@ static void WI_loadUnloadData(load_callback_t callback)
for (i=0;i<10;i++)
{
// numbers 0-9
- sprintf(name, DEH_String("WINUM%d"), i);
+ DEH_snprintf(name, 9, "WINUM%d", i);
callback(name, &num[i]);
}
@@ -1665,13 +1664,13 @@ static void WI_loadUnloadData(load_callback_t callback)
callback(DEH_String("WICOLON"), &colon);
// "time"
- callback(DEH_String("WITIME"), &timepatch);
+ callback(DEH_String("WITIME"), &timepatch);
// "sucks"
- callback(DEH_String("WISUCKS"), &sucks);
+ callback(DEH_String("WISUCKS"), &sucks);
// "par"
- callback(DEH_String("WIPAR"), &par);
+ callback(DEH_String("WIPAR"), &par);
// "killers" (vertical)
callback(DEH_String("WIKILRS"), &killers);
@@ -1680,16 +1679,16 @@ static void WI_loadUnloadData(load_callback_t callback)
callback(DEH_String("WIVCTMS"), &victims);
// "total"
- callback(DEH_String("WIMSTT"), &total);
+ callback(DEH_String("WIMSTT"), &total);
for (i=0 ; i<MAXPLAYERS ; i++)
{
// "1,2,3,4"
- sprintf(name, DEH_String("STPB%d"), i);
+ DEH_snprintf(name, 9, "STPB%d", i);
callback(name, &p[i]);
// "1,2,3,4"
- sprintf(name, DEH_String("WIBP%d"), i+1);
+ DEH_snprintf(name, 9, "WIBP%d", i+1);
callback(name, &bp[i]);
}
@@ -1697,19 +1696,21 @@ static void WI_loadUnloadData(load_callback_t callback)
if (gamemode == commercial)
{
- strcpy(name, DEH_String("INTERPIC"));
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
}
else if (gamemode == retail && wbs->epsd == 3)
{
- strcpy(name, DEH_String("INTERPIC"));
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
}
- else
+ else
{
- sprintf(name, DEH_String("WIMAP%d"), wbs->epsd);
+ DEH_snprintf(name, 9, "WIMAP%d", wbs->epsd);
}
-
+
// Draw backdrop and save to a temporary buffer
-
+
callback(name, &background);
}
@@ -1722,7 +1723,7 @@ void WI_loadData(void)
{
if (gamemode == commercial)
{
- NUMCMAPS = 32;
+ NUMCMAPS = 32;
lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS,
PU_STATIC, NULL);
}
diff --git a/src/heretic/.gitignore b/src/heretic/.gitignore
index d7e732ad..76092240 100644
--- a/src/heretic/.gitignore
+++ b/src/heretic/.gitignore
@@ -1,7 +1,6 @@
Makefile
Makefile.in
.deps
-*.rc
-chocolate-doom
-chocolate-server
-*.exe
+tags
+TAGS
+
diff --git a/src/heretic/Makefile.am b/src/heretic/Makefile.am
index 2a2f8245..e56ee806 100644
--- a/src/heretic/Makefile.am
+++ b/src/heretic/Makefile.am
@@ -20,6 +20,7 @@ info.c info.h \
in_lude.c \
m_random.c m_random.h \
mn_menu.c \
+ p_action.h \
p_ceilng.c \
p_doors.c \
p_enemy.c \
@@ -55,5 +56,15 @@ EXTRA_DIST= \
i_sound.c \
i_ibm.c
-libheretic_a_SOURCES=$(SOURCE_FILES)
+FEATURE_DEHACKED_SOURCE_FILES = \
+deh_ammo.c \
+deh_frame.c \
+deh_htext.c \
+deh_htic.c \
+deh_sound.c \
+deh_thing.c \
+deh_weapon.c
+
+libheretic_a_SOURCES=$(SOURCE_FILES) \
+ $(FEATURE_DEHACKED_SOURCE_FILES)
diff --git a/src/heretic/am_map.c b/src/heretic/am_map.c
index 99a8e206..aae30cc9 100644
--- a/src/heretic/am_map.c
+++ b/src/heretic/am_map.c
@@ -27,6 +27,7 @@
#include <stdio.h>
#include "doomdef.h"
+#include "deh_str.h"
#include "i_video.h"
#include "m_controls.h"
#include "p_local.h"
@@ -408,7 +409,7 @@ void AM_loadPics(void)
sprintf(namebuf, "AMMNUM%d", i);
marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
}*/
- maplump = W_CacheLumpName("AUTOPAGE", PU_STATIC);
+ maplump = W_CacheLumpName(DEH_String("AUTOPAGE"), PU_STATIC);
}
/*void AM_unloadPics(void)
@@ -1473,6 +1474,7 @@ void AM_drawCrosshair(int color)
void AM_Drawer(void)
{
+ char *level_name;
int numepisodes;
if (!automapactive)
@@ -1505,7 +1507,8 @@ void AM_Drawer(void)
if (gameepisode <= numepisodes && gamemap < 10)
{
- MN_DrTextA(LevelNames[(gameepisode - 1) * 9 + gamemap - 1], 20, 145);
+ level_name = LevelNames[(gameepisode - 1) * 9 + gamemap - 1];
+ MN_DrTextA(DEH_String(level_name), 20, 145);
}
// I_Update();
// V_MarkRect(f_x, f_y, f_w, f_h);
diff --git a/src/heretic/ct_chat.c b/src/heretic/ct_chat.c
index 75fa6035..8059b74d 100644
--- a/src/heretic/ct_chat.c
+++ b/src/heretic/ct_chat.c
@@ -29,6 +29,7 @@
#include <ctype.h>
#include "doomdef.h"
#include "doomkeys.h"
+#include "deh_str.h"
#include "p_local.h"
#include "s_sound.h"
#include "v_video.h"
@@ -115,7 +116,7 @@ void CT_Init(void)
memset(plr_lastmsg[i], 0, MESSAGESIZE);
memset(chat_msg[i], 0, MESSAGESIZE);
}
- FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+ FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1;
return;
}
@@ -300,7 +301,9 @@ void CT_Ticker(void)
CT_AddChar(i, 0); // set the end of message character
if (numplayers > 2)
{
- strcpy(plr_lastmsg[i], CT_FromPlrText[i]);
+ strncpy(plr_lastmsg[i], DEH_String(CT_FromPlrText[i]),
+ MESSAGESIZE + 9);
+ plr_lastmsg[i][MESSAGESIZE + 8] = '\0';
strcat(plr_lastmsg[i], chat_msg[i]);
}
else
@@ -320,13 +323,13 @@ void CT_Ticker(void)
if (numplayers > 1)
{
P_SetMessage(&players[consoleplayer],
- "-MESSAGE SENT-", true);
+ DEH_String("-MESSAGE SENT-"), true);
S_StartSound(NULL, sfx_chat);
}
else
{
P_SetMessage(&players[consoleplayer],
- "THERE ARE NO OTHER PLAYERS IN THE GAME!",
+ DEH_String("THERE ARE NO OTHER PLAYERS IN THE GAME!"),
true);
S_StartSound(NULL, sfx_chat);
}
@@ -376,7 +379,7 @@ void CT_Drawer(void)
x += patch->width;
}
}
- V_DrawPatch(x, 10, W_CacheLumpName("FONTA59", PU_CACHE));
+ V_DrawPatch(x, 10, W_CacheLumpName(DEH_String("FONTA59"), PU_CACHE));
BorderTopRefresh = true;
UpdateState |= I_MESSAGES;
}
diff --git a/src/heretic/d_main.c b/src/heretic/d_main.c
index 10f5fd3e..169a86ea 100644
--- a/src/heretic/d_main.c
+++ b/src/heretic/d_main.c
@@ -33,6 +33,7 @@
#include "config.h"
#include "ct_chat.h"
#include "doomdef.h"
+#include "deh_main.h"
#include "d_iwad.h"
#include "i_endoom.h"
#include "i_joystick.h"
@@ -45,6 +46,7 @@
#include "m_controls.h"
#include "p_local.h"
#include "s_sound.h"
+#include "w_main.h"
#include "v_video.h"
#define STARTUP_WINDOW_X 17
@@ -184,12 +186,12 @@ void D_Display(void)
{
if (!netgame)
{
- V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName("PAUSED",
+ V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName(DEH_String("PAUSED"),
PU_CACHE));
}
else
{
- V_DrawPatch(160, 70, W_CacheLumpName("PAUSED", PU_CACHE));
+ V_DrawPatch(160, 70, W_CacheLumpName(DEH_String("PAUSED"), PU_CACHE));
}
}
// Handle player messages
@@ -315,7 +317,7 @@ void D_PageDrawer(void)
V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE));
if (demosequence == 1)
{
- V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE));
+ V_DrawPatch(4, 160, W_CacheLumpName(DEH_String("ADVISOR"), PU_CACHE));
}
UpdateState |= I_FULLSCRN;
}
@@ -347,45 +349,45 @@ void D_DoAdvanceDemo(void)
case 0:
pagetic = 210;
gamestate = GS_DEMOSCREEN;
- pagename = "TITLE";
+ pagename = DEH_String("TITLE");
S_StartSong(mus_titl, false);
break;
case 1:
pagetic = 140;
gamestate = GS_DEMOSCREEN;
- pagename = "TITLE";
+ pagename = DEH_String("TITLE");
break;
case 2:
BorderNeedRefresh = true;
UpdateState |= I_FULLSCRN;
- G_DeferedPlayDemo("demo1");
+ G_DeferedPlayDemo(DEH_String("demo1"));
break;
case 3:
pagetic = 200;
gamestate = GS_DEMOSCREEN;
- pagename = "CREDIT";
+ pagename = DEH_String("CREDIT");
break;
case 4:
BorderNeedRefresh = true;
UpdateState |= I_FULLSCRN;
- G_DeferedPlayDemo("demo2");
+ G_DeferedPlayDemo(DEH_String("demo2"));
break;
case 5:
pagetic = 200;
gamestate = GS_DEMOSCREEN;
if (gamemode == shareware)
{
- pagename = "ORDER";
+ pagename = DEH_String("ORDER");
}
else
{
- pagename = "CREDIT";
+ pagename = DEH_String("CREDIT");
}
break;
case 6:
BorderNeedRefresh = true;
UpdateState |= I_FULLSCRN;
- G_DeferedPlayDemo("demo3");
+ G_DeferedPlayDemo(DEH_String("demo3"));
break;
}
}
@@ -638,7 +640,7 @@ void initStartup(void)
// Blit main screen
textScreen = TXT_GetScreenData();
- loading = W_CacheLumpName("LOADING", PU_CACHE);
+ loading = W_CacheLumpName(DEH_String("LOADING"), PU_CACHE);
memcpy(textScreen, loading, 4000);
// Print version string
@@ -698,7 +700,7 @@ void tprintf(char *msg, int initflag)
// haleyjd: moved up, removed WATCOMC code
void CleanExit(void)
{
- printf("Exited from HERETIC.\n");
+ DEH_printf("Exited from HERETIC.\n");
exit(1);
}
@@ -746,6 +748,7 @@ void D_BindVariables(void)
M_BindBaseControls();
M_BindHereticControls();
M_BindWeaponControls();
+ M_BindChatControls(MAXPLAYERS);
M_BindMenuControls();
M_BindMapControls();
@@ -782,7 +785,7 @@ static void D_Endoom(void)
return;
}
- endoom_data = W_CacheLumpName("ENDTEXT", PU_STATIC);
+ endoom_data = W_CacheLumpName(DEH_String("ENDTEXT"), PU_STATIC);
I_Endoom(endoom_data);
}
@@ -847,7 +850,7 @@ void D_DoomMain(void)
//
// init subsystems
//
- printf("V_Init: allocate screens.\n");
+ DEH_printf("V_Init: allocate screens.\n");
V_Init();
// Check for -CDROM
@@ -872,7 +875,7 @@ void D_DoomMain(void)
if (cdrom)
{
- M_SetConfigDir("c:\\heretic.cd\\");
+ M_SetConfigDir(DEH_String("c:\\heretic.cd"));
}
else
{
@@ -880,17 +883,22 @@ void D_DoomMain(void)
}
// Load defaults before initing other systems
- printf("M_LoadDefaults: Load system defaults.\n");
+ DEH_printf("M_LoadDefaults: Load system defaults.\n");
D_BindVariables();
M_SetConfigFilenames("heretic.cfg", PROGRAM_PREFIX "heretic.cfg");
M_LoadDefaults();
I_AtExit(M_SaveDefaults, false);
- printf("Z_Init: Init zone memory allocation daemon.\n");
+ DEH_printf("Z_Init: Init zone memory allocation daemon.\n");
Z_Init();
- printf("W_Init: Init WADfiles.\n");
+#ifdef FEATURE_DEHACKED
+ printf("DEH_Init: Init Dehacked support.\n");
+ DEH_Init();
+#endif
+
+ DEH_printf("W_Init: Init WADfiles.\n");
iwadfile = D_FindIWAD(IWAD_MASK_HERETIC, &gamemission);
@@ -901,24 +909,7 @@ void D_DoomMain(void)
}
D_AddFile(iwadfile);
-
- // -FILE [filename] [filename] ...
- // Add files to the wad list.
- p = M_CheckParm("-file");
-
- if (p)
- {
- char *filename;
-
- // the parms after p are wadfile/lump names, until end of parms
- // or another - preceded parm
-
- while (++p != myargc && myargv[p][0] != '-')
- {
- filename = D_FindWADByName(myargv[p]);
- D_AddFile(filename);
- }
- }
+ W_ParseCommandLine();
p = M_CheckParm("-playdemo");
if (!p)
@@ -927,12 +918,12 @@ void D_DoomMain(void)
}
if (p && p < myargc - 1)
{
- sprintf(file, "%s.lmp", myargv[p + 1]);
+ DEH_snprintf(file, sizeof(file), "%s.lmp", myargv[p + 1]);
D_AddFile(file);
- printf("Playing demo %s.lmp.\n", myargv[p + 1]);
+ DEH_printf("Playing demo %s.lmp.\n", myargv[p + 1]);
}
- if (W_CheckNumForName("E2M1") == -1)
+ if (W_CheckNumForName(DEH_String("E2M1")) == -1)
{
gamemode = shareware;
gamedescription = "Heretic (shareware)";
@@ -960,54 +951,55 @@ void D_DoomMain(void)
//
smsg[0] = 0;
if (deathmatch)
- status("DeathMatch...");
+ status(DEH_String("DeathMatch..."));
if (nomonsters)
- status("No Monsters...");
+ status(DEH_String("No Monsters..."));
if (respawnparm)
- status("Respawning...");
+ status(DEH_String("Respawning..."));
if (autostart)
{
char temp[64];
- sprintf(temp, "Warp to Episode %d, Map %d, Skill %d ",
- startepisode, startmap, startskill + 1);
+ DEH_snprintf(temp, sizeof(temp),
+ "Warp to Episode %d, Map %d, Skill %d ",
+ startepisode, startmap, startskill + 1);
status(temp);
}
wadprintf(); // print the added wadfiles
- tprintf("MN_Init: Init menu system.\n", 1);
+ tprintf(DEH_String("MN_Init: Init menu system.\n"), 1);
MN_Init();
CT_Init();
- tprintf("R_Init: Init Heretic refresh daemon.", 1);
- hprintf("Loading graphics");
+ tprintf(DEH_String("R_Init: Init Heretic refresh daemon."), 1);
+ hprintf(DEH_String("Loading graphics"));
R_Init();
tprintf("\n", 0);
- tprintf("P_Init: Init Playloop state.\n", 1);
- hprintf("Init game engine.");
+ tprintf(DEH_String("P_Init: Init Playloop state.\n"), 1);
+ hprintf(DEH_String("Init game engine."));
P_Init();
IncThermo();
- tprintf("I_Init: Setting up machine state.\n", 1);
+ tprintf(DEH_String("I_Init: Setting up machine state.\n"), 1);
I_CheckIsScreensaver();
I_InitTimer();
I_InitJoystick();
IncThermo();
- tprintf("S_Init: Setting up sound.\n", 1);
+ tprintf(DEH_String("S_Init: Setting up sound.\n"), 1);
S_Init();
//IO_StartupTimer();
S_Start();
- tprintf("D_CheckNetGame: Checking network game status.\n", 1);
- hprintf("Checking network game status.");
+ tprintf(DEH_String("D_CheckNetGame: Checking network game status.\n"), 1);
+ hprintf(DEH_String("Checking network game status."));
D_CheckNetGame();
IncThermo();
// haleyjd: removed WATCOMC
- tprintf("SB_Init: Loading patches.\n", 1);
+ tprintf(DEH_String("SB_Init: Loading patches.\n"), 1);
SB_Init();
IncThermo();
diff --git a/src/heretic/deh_ammo.c b/src/heretic/deh_ammo.c
new file mode 100644
index 00000000..fe86c757
--- /dev/null
+++ b/src/heretic/deh_ammo.c
@@ -0,0 +1,122 @@
+// 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);
+
+ if (!strcasecmp(variable_name, "Per ammo"))
+ {
+ // Heretic doesn't have a "per clip" ammo array, instead
+ // it is per weapon. However, the weapon number lines
+ // up with the ammo number if we add one.
+
+ GetWeaponAmmo[ammo_number + 1] = 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, maxammo[i]);
+ }
+
+ for (i=0; i<NUMWEAPONS; ++i)
+ {
+ MD5_UpdateInt32(context, GetWeaponAmmo[i]);
+ }
+}
+
+deh_section_t deh_section_ammo =
+{
+ "Ammo",
+ NULL,
+ DEH_AmmoStart,
+ DEH_AmmoParseLine,
+ NULL,
+ DEH_AmmoMD5Hash,
+};
+
diff --git a/src/heretic/deh_frame.c b/src/heretic/deh_frame.c
new file mode 100644
index 00000000..8623ab0c
--- /dev/null
+++ b/src/heretic/deh_frame.c
@@ -0,0 +1,344 @@
+// 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 "info.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+#include "deh_htic.h"
+
+#include "p_action.h"
+
+typedef struct
+{
+ int offsets[deh_hhe_num_versions];
+ void (*func)();
+} hhe_action_pointer_t;
+
+// Offsets of action pointers within the Heretic executables.
+// Different versions have different offsets.
+// (Seriously Greg, was this really necessary? What was wrong with the
+// "copying action pointer from another frame" technique used in dehacked?)
+
+// Offset Action function
+// v1.0 v1.2 v1.3
+
+static const hhe_action_pointer_t action_pointers[] =
+{
+ { { 77680, 80144, 80208 }, A_AccTeleGlitter },
+ { { 78608, 81104, 81168 }, A_AddPlayerCorpse },
+ { { 115808, 118000, 118240 }, A_AddPlayerRain },
+ { { 112272, 114480, 114720 }, A_BeakAttackPL1 },
+ { { 112448, 114656, 114896 }, A_BeakAttackPL2 },
+ { { 111856, 114176, 114416 }, A_BeakRaise },
+ { { 111568, 113888, 114128 }, A_BeakReady },
+ { { 74640, 77120, 77184 }, A_BeastAttack },
+ { { 70480, 72992, 73056 }, A_BeastPuff },
+ { { 73120, 75600, 75664 }, A_BlueSpark },
+ { { 115456, 117648, 117888 }, A_BoltSpark },
+ { { 77344, 79808, 79872 }, A_BossDeath },
+ { { 69328, 71856, 71920 }, A_Chase },
+ { { 0, 80976, 81040 }, A_CheckBurnGone },
+ { { 78480, 80944, 81008 }, A_CheckSkullDone },
+ { { 78448, 80912, 80976 }, A_CheckSkullFloor },
+ { { 71376, 73888, 73952 }, A_ChicAttack },
+ { { 71488, 74000, 74064 }, A_ChicChase },
+ { { 71456, 73968, 74032 }, A_ChicLook },
+ { { 71520, 74032, 74096 }, A_ChicPain },
+ { { 75792, 78208, 78272 }, A_ClinkAttack },
+ { { 108432, 110816, 111056 }, A_ContMobjSound },
+ { { 114752, 116944, 117184 }, A_DeathBallImpact },
+ { { 70016, 72528, 72592 }, A_DripBlood },
+ { { 77472, 79936, 80000 }, A_ESound },
+ { { 76784, 79248, 79312 }, A_Explode },
+ { { 69872, 72400, 72464 }, A_FaceTarget },
+ { { 71568, 74080, 74144 }, A_Feathers },
+ { { 112928, 115136, 115376 }, A_FireBlasterPL1 },
+ { { 113072, 115280, 115520 }, A_FireBlasterPL2 },
+ { { 115232, 117424, 117664 }, A_FireCrossbowPL1 },
+ { { 115312, 117504, 117744 }, A_FireCrossbowPL2 },
+ { { 113152, 115360, 115600 }, A_FireGoldWandPL1 },
+ { { 113296, 115504, 115744 }, A_FireGoldWandPL2 },
+ { { 113760, 115968, 116208 }, A_FireMacePL1 },
+ { { 114624, 116816, 117056 }, A_FireMacePL2 },
+ { { 116368, 118544, 118784 }, A_FirePhoenixPL1 },
+ { { 116736, 118896, 119136 }, A_FirePhoenixPL2 },
+ { { 115568, 117760, 118000 }, A_FireSkullRodPL1 },
+ { { 115648, 117840, 118080 }, A_FireSkullRodPL2 },
+ { { 117120, 119280, 119520 }, A_FlameEnd },
+ { { 78704, 81200, 81264 }, A_FlameSnd },
+ { { 117152, 119312, 119552 }, A_FloatPuff },
+ { { 78512, 81008, 81072 }, A_FreeTargMobj },
+ { { 117184, 119344, 119584 }, A_GauntletAttack },
+ { { 73232, 75712, 75776 }, A_GenWizard },
+ { { 75872, 78304, 78368 }, A_GhostOff },
+ { { 74752, 77232, 77296 }, A_HeadAttack },
+ { { 75488, 77984, 78048 }, A_HeadFireGrow },
+ { { 75328, 77824, 77888 }, A_HeadIceImpact },
+ { { 116336, 118512, 118752 }, A_HideInCeiling },
+ { { 78736, 81232, 81296 }, A_HideThing },
+ { { 70976, 73488, 73552 }, A_ImpDeath },
+ { { 70304, 72816, 72880 }, A_ImpExplode },
+ { { 70592, 73104, 73168 }, A_ImpMeAttack },
+ { { 70672, 73184, 73248 }, A_ImpMsAttack },
+ { { 70880, 73392, 73456 }, A_ImpMsAttack2 },
+ { { 71024, 73536, 73600 }, A_ImpXDeath1 },
+ { { 71072, 73584, 73648 }, A_ImpXDeath2 },
+ { { 77728, 80192, 80256 }, A_InitKeyGizmo },
+ { { 116720, 118880, 119120 }, A_InitPhoenixPL2 },
+ { { 70160, 72672, 72736 }, A_KnightAttack },
+ { { 117648, 119824, 120064 }, A_Light0 },
+ { { 69200, 71728, 71792 }, A_Look },
+ { { 111760, 114080, 114320 }, A_Lower },
+ { { 114032, 116224, 116464 }, A_MaceBallImpact },
+ { { 114192, 116384, 116624 }, A_MaceBallImpact2 },
+ { { 113904, 116112, 116352 }, A_MacePL1Check },
+ { { 77104, 79568, 79632 }, A_MakePod },
+ { { 73648, 76128, 76192 }, A_MinotaurAtk1 },
+ { { 74112, 76592, 76656 }, A_MinotaurAtk2 },
+ { { 74352, 76832, 76896 }, A_MinotaurAtk3 },
+ { { 74032, 76512, 76576 }, A_MinotaurCharge },
+ { { 73760, 76240, 76304 }, A_MinotaurDecide },
+ { { 74528, 77008, 77072 }, A_MntrFloorFire },
+ { { 71808, 74288, 74352 }, A_MummyAttack },
+ { { 71920, 74400, 74464 }, A_MummyAttack2 },
+ { { 72016, 74496, 74560 }, A_MummyFX1Seek },
+ { { 72048, 74528, 74592 }, A_MummySoul },
+ { { 76400, 78832, 78896 }, A_NoBlocking },
+ { { 69984, 72496, 72560 }, A_Pain },
+ { { 116496, 118656, 118896 }, A_PhoenixPuff },
+ { { 76896, 79360, 79424 }, A_PodPain },
+ { { 116272, 118448, 118688 }, A_RainImpact },
+ { { 111920, 114240, 114480 }, A_Raise },
+ { { 111696, 114016, 114256 }, A_ReFire },
+ { { 77056, 79520, 79584 }, A_RemovePod },
+ { { 116480, 0, 0 }, A_RemovedPhoenixFunc },
+ { { 81952, 84464, 84528 }, A_RestoreArtifact },
+ { { 82048, 84544, 84608 }, A_RestoreSpecialThing1 },
+ { { 82128, 84592, 84656 }, A_RestoreSpecialThing2 },
+ { { 76144, 78576, 78640 }, A_Scream },
+ { { 117104, 119264, 119504 }, A_ShutdownPhoenixPL2 },
+ { { 78288, 80752, 80816 }, A_SkullPop },
+ { { 115776, 117968, 118208 }, A_SkullRodPL2Seek },
+ { { 115984, 118176, 118416 }, A_SkullRodStorm },
+ { { 75632, 78048, 78112 }, A_SnakeAttack },
+ { { 75712, 78128, 78192 }, A_SnakeAttack2 },
+ { { 72144, 74624, 74688 }, A_Sor1Chase },
+ { { 72096, 74576, 74640 }, A_Sor1Pain },
+ { { 73392, 75872, 75936 }, A_Sor2DthInit },
+ { { 73424, 75904, 75968 }, A_Sor2DthLoop },
+ { { 73584, 76064, 76128 }, A_SorDBon },
+ { { 73552, 76032, 76096 }, A_SorDExp },
+ { { 73520, 76000, 76064 }, A_SorDSph },
+ { { 73488, 75968, 76032 }, A_SorRise },
+ { { 73616, 76096, 76160 }, A_SorSightSnd },
+ { { 73456, 75936, 76000 }, A_SorZap },
+ { { 72480, 74960, 75024 }, A_SorcererRise },
+ { { 115088, 117280, 117520 }, A_SpawnRippers },
+ { { 77520, 79984, 80048 }, A_SpawnTeleGlitter },
+ { { 77600, 80064, 80128 }, A_SpawnTeleGlitter2 },
+ { { 72192, 74672, 74736 }, A_Srcr1Attack },
+ { { 72896, 75376, 75440 }, A_Srcr2Attack },
+ { { 72816, 75296, 75360 }, A_Srcr2Decide },
+ { { 112640, 114848, 115088 }, A_StaffAttackPL1 },
+ { { 112784, 114992, 115232 }, A_StaffAttackPL2 },
+ { { 78752, 81248, 81312 }, A_UnHideThing },
+ { { 78080, 80544, 80608 }, A_VolcBallImpact },
+ { { 77856, 80320, 80384 }, A_VolcanoBlast },
+ { { 77824, 80288, 80352 }, A_VolcanoSet },
+ { { 111168, 113488, 113728 }, A_WeaponReady },
+ { { 75168, 77664, 77728 }, A_WhirlwindSeek },
+ { { 75888, 78320, 78384 }, A_WizAtk1 },
+ { { 75920, 78352, 78416 }, A_WizAtk2 },
+ { { 75952, 78384, 78448 }, A_WizAtk3 },
+};
+
+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_MAPPING("Unknown 1", misc1)
+ DEH_MAPPING("Unknown 2", misc2)
+DEH_END_MAPPING
+
+static void DEH_FrameInit(void)
+{
+ // Bit of a hack here:
+ DEH_HereticInit();
+}
+
+static void *DEH_FrameStart(deh_context_t *context, char *line)
+{
+ int frame_number = 0;
+ int mapped_frame_number;
+ state_t *state;
+
+ if (sscanf(line, "Frame %i", &frame_number) != 1)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ // Map the HHE frame number (which assumes a Heretic 1.0 state table)
+ // to the internal frame number (which is is the Heretic 1.3 state table):
+
+ mapped_frame_number = DEH_MapHereticFrameNumber(frame_number);
+
+ if (mapped_frame_number < 0 || mapped_frame_number >= DEH_HERETIC_NUMSTATES)
+ {
+ DEH_Warning(context, "Invalid frame number: %i", frame_number);
+ return NULL;
+ }
+
+ state = &states[mapped_frame_number];
+
+ return state;
+}
+
+static boolean GetActionPointerForOffset(int offset, void **result)
+{
+ int i;
+
+ // Special case.
+
+ if (offset == 0)
+ {
+ *result = NULL;
+ return true;
+ }
+
+ for (i=0; i<arrlen(action_pointers); ++i)
+ {
+ if (action_pointers[i].offsets[deh_hhe_version] == offset)
+ {
+ *result = action_pointers[i].func;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// If an invalid action pointer is specified, the patch may be for a
+// different version from the version we are currently set to. Try to
+// suggest a different version to use.
+
+static void SuggestOtherVersions(unsigned int offset)
+{
+ unsigned int i, v;
+
+ for (i=0; i<arrlen(action_pointers); ++i)
+ {
+ for (v=0; v<deh_hhe_num_versions; ++v)
+ {
+ if (action_pointers[i].offsets[v] == offset)
+ {
+ DEH_SuggestHereticVersion(v);
+ }
+ }
+ }
+}
+
+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);
+
+ // Action pointer field is a special case:
+
+ if (!strcasecmp(variable_name, "Action pointer"))
+ {
+ void *func;
+
+ if (!GetActionPointerForOffset(ivalue, &func))
+ {
+ SuggestOtherVersions(ivalue);
+ DEH_Error(context, "Unknown action pointer: %i", ivalue);
+ return;
+ }
+
+ state->action = func;
+ }
+ else
+ {
+ // "Next frame" numbers need to undergo mapping.
+
+ if (!strcasecmp(variable_name, "Next frame"))
+ {
+ ivalue = DEH_MapHereticFrameNumber(ivalue);
+ }
+
+ 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",
+ DEH_FrameInit,
+ DEH_FrameStart,
+ DEH_FrameParseLine,
+ NULL,
+ DEH_FrameMD5Sum,
+};
+
diff --git a/src/heretic/deh_htext.c b/src/heretic/deh_htext.c
new file mode 100644
index 00000000..5dfddac3
--- /dev/null
+++ b/src/heretic/deh_htext.c
@@ -0,0 +1,856 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2005-2010 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 Text substitution sections in dehacked files
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <string.h>
+
+#include "doomtype.h"
+#include "dstrings.h"
+
+#include "z_zone.h"
+
+#include "deh_defs.h"
+#include "deh_io.h"
+#include "deh_htic.h"
+#include "deh_main.h"
+
+//
+// Ok, Greg, the action pointers thing was bad enough, but this really
+// takes the biscuit. Why does HHE's text replacement address strings
+// by offset??!! The dehacked way was much nicer, why change it?
+//
+
+typedef struct
+{
+ unsigned int offsets[deh_hhe_num_versions];
+ char *string;
+} hhe_string_t;
+
+// Offsets String
+// v1.0 v1.2 v1.3
+
+static const hhe_string_t strings[] =
+{
+ { { 228, 228, 228 }, "PLAYPAL" },
+ { { 1240, 1252, 1252 }, "E1M1: THE DOCKS" },
+ { { 1260, 1272, 1272 }, "E1M2: THE DUNGEONS" },
+ { { 1280, 1292, 1292 }, "E1M3: THE GATEHOUSE" },
+ { { 1304, 1316, 1316 }, "E1M4: THE GUARD TOWER" },
+ { { 1328, 1340, 1340 }, "E1M5: THE CITADEL" },
+ { { 1348, 1360, 1360 }, "E1M6: THE CATHEDRAL" },
+ { { 1372, 1384, 1384 }, "E1M7: THE CRYPTS" },
+ { { 1392, 1404, 1404 }, "E1M8: HELL'S MAW" },
+ { { 1412, 1424, 1424 }, "E1M9: THE GRAVEYARD" },
+ { { 1436, 1448, 1448 }, "E2M1: THE CRATER" },
+ { { 1456, 1468, 1468 }, "E2M2: THE LAVA PITS" },
+ { { 1480, 1492, 1492 }, "E2M3: THE RIVER OF FIRE" },
+ { { 1508, 1520, 1520 }, "E2M4: THE ICE GROTTO" },
+ { { 1532, 1544, 1544 }, "E2M5: THE CATACOMBS" },
+ { { 1556, 1568, 1568 }, "E2M6: THE LABYRINTH" },
+ { { 1580, 1592, 1592 }, "E2M7: THE GREAT HALL" },
+ { { 1604, 1616, 1616 }, "E2M8: THE PORTALS OF CHAOS" },
+ { { 1632, 1644, 1644 }, "E2M9: THE GLACIER" },
+ { { 1652, 1664, 1664 }, "E3M1: THE STOREHOUSE" },
+ { { 1676, 1688, 1688 }, "E3M2: THE CESSPOOL" },
+ { { 1696, 1708, 1708 }, "E3M3: THE CONFLUENCE" },
+ { { 1720, 1732, 1732 }, "E3M4: THE AZURE FORTRESS" },
+ { { 1748, 1760, 1760 }, "E3M5: THE OPHIDIAN LAIR" },
+ { { 1776, 1788, 1788 }, "E3M6: THE HALLS OF FEAR" },
+ { { 1804, 1816, 1816 }, "E3M7: THE CHASM" },
+ { { 1824, 1836, 1836 }, "E3M8: D'SPARIL'S KEEP" },
+ { { 1848, 1860, 1860 }, "E3M9: THE AQUIFER" },
+ { { 0, 1880, 1880 }, "E4M1: CATAFALQUE" },
+ { { 0, 1900, 1900 }, "E4M2: BLOCKHOUSE" },
+ { { 0, 1920, 1920 }, "E4M3: AMBULATORY" },
+ { { 0, 1940, 1940 }, "E4M4: SEPULCHER" },
+ { { 0, 1960, 1960 }, "E4M5: GREAT STAIR" },
+ { { 0, 1980, 1980 }, "E4M6: HALLS OF THE APOSTATE" },
+ { { 0, 2012, 2012 }, "E4M7: RAMPARTS OF PERDITION" },
+ { { 0, 2044, 2044 }, "E4M8: SHATTERED BRIDGE" },
+ { { 0, 2068, 2068 }, "E4M9: MAUSOLEUM" },
+ { { 0, 2088, 2088 }, "E5M1: OCHRE CLIFFS" },
+ { { 0, 2108, 2108 }, "E5M2: RAPIDS" },
+ { { 0, 2124, 2124 }, "E5M3: QUAY" },
+ { { 0, 2136, 2136 }, "E5M4: COURTYARD" },
+ { { 0, 2156, 2156 }, "E5M5: HYDRATYR" },
+ { { 0, 2172, 2172 }, "E5M6: COLONNADE" },
+ { { 0, 2192, 2192 }, "E5M7: FOETID MANSE" },
+ { { 0, 2212, 2212 }, "E5M8: FIELD OF JUDGEMENT" },
+ { { 0, 2240, 2240 }, "E5M9: SKEIN OF D'SPARIL" },
+ { { 1868, 2268, 2268 }, "AUTOPAGE" },
+ { { 1880, 2280, 2280 }, "FOLLOW MODE ON" },
+ { { 1896, 2296, 2296 }, "FOLLOW MODE OFF" },
+ { { 1924, 2324, 2324 }, "GREEN: " },
+ { { 1936, 2336, 2336 }, "YELLOW: " },
+ { { 1948, 2348, 2348 }, "RED: " },
+ { { 1956, 2356, 2356 }, "BLUE: " },
+ { { 1964, 2364, 2364 }, "FONTA_S" },
+ { { 1972, 2372, 2372 }, "-MESSAGE SENT-" },
+ { { 1988, 2388, 2388 }, "THERE ARE NO OTHER PLAYERS IN THE GAME!" },
+ { { 2028, 2428, 2428 }, "FONTA59" },
+ { { 2036, 2504, 2504 }, "PAUSED" },
+ { { 2072, 2540, 2540 }, "ADVISOR" },
+ { { 2080, 2548, 2548 }, "TITLE" },
+ { { 2088, 2556, 2556 }, "demo1" },
+ { { 2096, 2564, 2564 }, "CREDIT" },
+ { { 2104, 2572, 2572 }, "demo2" },
+ { { 2112, 2580, 2580 }, "ORDER" },
+ { { 2120, 2588, 2588 }, "demo3" },
+ { { 2304, 2696, 2696 }, "Exited from HERETIC.\n" },
+ { { 2412, 2800, 2800 }, "c:\\heretic.cd" },
+ { { 2528, 2916, 2916 }, "Playing demo %s.lmp.\n" },
+ { { 2592, 2980, 2980 }, "V_Init: allocate screens.\n" },
+ { { 2620, 3008, 3008 }, "M_LoadDefaults: Load system defaults.\n" },
+ { { 2660, 3048, 3048 }, "Z_Init: Init zone memory allocation daemon.\n" },
+ { { 2708, 3096, 3096 }, "W_Init: Init WADfiles.\n" },
+ { { 2732, 3120, 3120 }, "E2M1" },
+ { { 0, 3128, 3128 }, "EXTENDED" },
+ { { 2740, 3140, 3140 }, "LOADING" },
+ { { 2748, 3148, 3148 }, "DeathMatch..." },
+ { { 2764, 3164, 3164 }, "No Monsters..." },
+ { { 2780, 3180, 3180 }, "Respawning..." },
+ { { 2796, 3196, 3196 }, "Warp to Episode %d, Map %d, Skill %d " },
+ { { 2836, 3236, 3236 }, "MN_Init: Init menu system.\n" },
+ { { 2864, 3264, 3264 }, "R_Init: Init Heretic refresh daemon." },
+ { { 2904, 3304, 3304 }, "Loading graphics" },
+ { { 2924, 3324, 3324 }, "P_Init: Init Playloop state." },
+ { { 2956, 3356, 3356 }, "Init game engine." },
+ { { 2976, 3376, 3376 }, "I_Init: Setting up machine state.\n" },
+ { { 3012, 3412, 3412 }, "D_CheckNetGame: Checking network game status.\n" },
+ { { 3060, 3460, 3460 }, "Checking network game status." },
+ { { 3092, 3492, 3492 }, "SB_Init: Loading patches.\n" },
+ { { 0, 3752, 3752 }, "PLAYER 1 LEFT THE GAME" },
+ { { 3508, 3932, 3932 }, "Network game synchronization aborted." },
+ { { 0, 3972, 3972 }, "Different DOOM versions cannot play a net game!" },
+ { { 3908, 4132, 4132 }, "SKY1" },
+ { { 3916, 4140, 4140 }, "SKY2" },
+ { { 3924, 4148, 4148 }, "SKY3" },
+ { { 3736, 4196, 4196 }, "NET GAME" },
+ { { 3748, 4208, 4208 }, "SAVE GAME" },
+ { { 3760, 4220, 4220 }, "Only %i deathmatch spots, 4 required" },
+ { { 3800, 4260, 4260 }, "version %i" },
+ { { 3828, 4372, 4372 }, "c:\\heretic.cd\\hticsav%d.hsg" },
+ { { 3856, 4400, 4400 }, "hticsav%d.hsg" },
+ { { 3896, 4416, 4416 }, "GAME SAVED" },
+ { { 4016, 4456, 4456 }, E1TEXT },
+ { { 4536, 4976, 4976 }, E2TEXT },
+ { { 5068, 5508, 5508 }, E3TEXT },
+ { { 0, 6072, 6072 }, E4TEXT },
+ { { 0, 6780, 6780 }, E5TEXT },
+ { { 5632, 7468, 7468 }, "FLOOR25" },
+ { { 5640, 7476, 7476 }, "FLATHUH1" },
+ { { 5652, 7488, 7488 }, "FLTWAWA2" },
+ { { 0, 7500, 7500 }, "FLOOR28" },
+ { { 0, 7508, 7508 }, "FLOOR08" },
+ { { 5664, 7516, 7516 }, "FONTA_S" },
+ { { 5704, 7524, 7524 }, "PLAYPAL" },
+ { { 5672, 7532, 7532 }, "FINAL1" },
+ { { 5680, 7540, 7540 }, "FINAL2" },
+ { { 5688, 7548, 7548 }, "E2PAL" },
+ { { 5696, 7556, 7556 }, "E2END" },
+ { { 7884, 7564, 7564 }, "TITLE" },
+ { { 5712, 7572, 7572 }, "ORDER" },
+ { { 0, 7580, 7580 }, "CREDIT" },
+ { { 5720, 7588, 7588 }, "IMPX" },
+ { { 5728, 7596, 7596 }, "ACLO" },
+ { { 5736, 7604, 7604 }, "PTN1" },
+ { { 5744, 7612, 7612 }, "SHLD" },
+ { { 5752, 7620, 7620 }, "SHD2" },
+ { { 5760, 7628, 7628 }, "BAGH" },
+ { { 5768, 7636, 7636 }, "SPMP" },
+ { { 5776, 7644, 7644 }, "INVS" },
+ { { 5784, 7652, 7652 }, "PTN2" },
+ { { 5792, 7660, 7660 }, "SOAR" },
+ { { 5800, 7668, 7668 }, "INVU" },
+ { { 5808, 7676, 7676 }, "PWBK" },
+ { { 5816, 7684, 7684 }, "EGGC" },
+ { { 5824, 7692, 7692 }, "EGGM" },
+ { { 5832, 7700, 7700 }, "FX01" },
+ { { 5840, 7708, 7708 }, "SPHL" },
+ { { 5848, 7716, 7716 }, "TRCH" },
+ { { 5856, 7724, 7724 }, "FBMB" },
+ { { 5864, 7732, 7732 }, "XPL1" },
+ { { 5872, 7740, 7740 }, "ATLP" },
+ { { 5880, 7748, 7748 }, "PPOD" },
+ { { 5888, 7756, 7756 }, "AMG1" },
+ { { 5896, 7764, 7764 }, "SPSH" },
+ { { 5904, 7772, 7772 }, "LVAS" },
+ { { 5912, 7780, 7780 }, "SLDG" },
+ { { 5920, 7788, 7788 }, "SKH1" },
+ { { 5928, 7796, 7796 }, "SKH2" },
+ { { 5936, 7804, 7804 }, "SKH3" },
+ { { 5944, 7812, 7812 }, "SKH4" },
+ { { 5952, 7820, 7820 }, "CHDL" },
+ { { 5960, 7828, 7828 }, "SRTC" },
+ { { 5968, 7836, 7836 }, "SMPL" },
+ { { 5976, 7844, 7844 }, "STGS" },
+ { { 5984, 7852, 7852 }, "STGL" },
+ { { 5992, 7860, 7860 }, "STCS" },
+ { { 6000, 7868, 7868 }, "STCL" },
+ { { 6008, 7876, 7876 }, "KFR1" },
+ { { 6016, 7884, 7884 }, "BARL" },
+ { { 6024, 7892, 7892 }, "BRPL" },
+ { { 6032, 7900, 7900 }, "MOS1" },
+ { { 6040, 7908, 7908 }, "MOS2" },
+ { { 6048, 7916, 7916 }, "WTRH" },
+ { { 6056, 7924, 7924 }, "HCOR" },
+ { { 6064, 7932, 7932 }, "KGZ1" },
+ { { 6072, 7940, 7940 }, "KGZB" },
+ { { 6080, 7948, 7948 }, "KGZG" },
+ { { 6088, 7956, 7956 }, "KGZY" },
+ { { 6096, 7964, 7964 }, "VLCO" },
+ { { 6104, 7972, 7972 }, "VFBL" },
+ { { 6112, 7980, 7980 }, "VTFB" },
+ { { 6120, 7988, 7988 }, "SFFI" },
+ { { 6128, 7996, 7996 }, "TGLT" },
+ { { 6136, 8004, 8004 }, "TELE" },
+ { { 6144, 8012, 8012 }, "STFF" },
+ { { 6152, 8020, 8020 }, "PUF3" },
+ { { 6160, 8028, 8028 }, "PUF4" },
+ { { 6168, 8036, 8036 }, "BEAK" },
+ { { 6176, 8044, 8044 }, "WGNT" },
+ { { 6184, 8052, 8052 }, "GAUN" },
+ { { 6192, 8060, 8060 }, "PUF1" },
+ { { 6200, 8068, 8068 }, "WBLS" },
+ { { 6208, 8076, 8076 }, "BLSR" },
+ { { 6216, 8084, 8084 }, "FX18" },
+ { { 6224, 8092, 8092 }, "FX17" },
+ { { 6232, 8100, 8100 }, "WMCE" },
+ { { 6240, 8108, 8108 }, "MACE" },
+ { { 6248, 8116, 8116 }, "FX02" },
+ { { 6256, 8124, 8124 }, "WSKL" },
+ { { 6264, 8132, 8132 }, "HROD" },
+ { { 6272, 8140, 8140 }, "FX00" },
+ { { 6280, 8148, 8148 }, "FX20" },
+ { { 6288, 8156, 8156 }, "FX21" },
+ { { 6296, 8164, 8164 }, "FX22" },
+ { { 6304, 8172, 8172 }, "FX23" },
+ { { 6312, 8180, 8180 }, "GWND" },
+ { { 6320, 8188, 8188 }, "PUF2" },
+ { { 6328, 8196, 8196 }, "WPHX" },
+ { { 6336, 8204, 8204 }, "PHNX" },
+ { { 6344, 8212, 8212 }, "FX04" },
+ { { 6352, 8220, 8220 }, "FX08" },
+ { { 6360, 8228, 8228 }, "FX09" },
+ { { 6368, 8236, 8236 }, "WBOW" },
+ { { 6376, 8244, 8244 }, "CRBW" },
+ { { 6384, 8252, 8252 }, "FX03" },
+ { { 6392, 8260, 8260 }, "BLOD" },
+ { { 6400, 8268, 8268 }, "PLAY" },
+ { { 6408, 8276, 8276 }, "FDTH" },
+ { { 6416, 8284, 8284 }, "BSKL" },
+ { { 6424, 8292, 8292 }, "CHKN" },
+ { { 6432, 8300, 8300 }, "MUMM" },
+ { { 6440, 8308, 8308 }, "FX15" },
+ { { 6448, 8316, 8316 }, "BEAS" },
+ { { 6456, 8324, 8324 }, "FRB1" },
+ { { 6464, 8332, 8332 }, "SNKE" },
+ { { 6472, 8340, 8340 }, "SNFX" },
+ { { 6480, 8348, 8348 }, "HEAD" },
+ { { 6488, 8356, 8356 }, "FX05" },
+ { { 6496, 8364, 8364 }, "FX06" },
+ { { 6504, 8372, 8372 }, "FX07" },
+ { { 6512, 8380, 8380 }, "CLNK" },
+ { { 6520, 8388, 8388 }, "WZRD" },
+ { { 6528, 8396, 8396 }, "FX11" },
+ { { 6536, 8404, 8404 }, "FX10" },
+ { { 6544, 8412, 8412 }, "KNIG" },
+ { { 6552, 8420, 8420 }, "SPAX" },
+ { { 6560, 8428, 8428 }, "RAXE" },
+ { { 6568, 8436, 8436 }, "SRCR" },
+ { { 6576, 8444, 8444 }, "FX14" },
+ { { 6584, 8452, 8452 }, "SOR2" },
+ { { 6592, 8460, 8460 }, "SDTH" },
+ { { 6600, 8468, 8468 }, "FX16" },
+ { { 6608, 8476, 8476 }, "MNTR" },
+ { { 6616, 8484, 8484 }, "FX12" },
+ { { 6624, 8492, 8492 }, "FX13" },
+ { { 6632, 8500, 8500 }, "AKYY" },
+ { { 6640, 8508, 8508 }, "BKYY" },
+ { { 6648, 8516, 8516 }, "CKYY" },
+ { { 6656, 8524, 8524 }, "AMG2" },
+ { { 6664, 8532, 8532 }, "AMM1" },
+ { { 6672, 8540, 8540 }, "AMM2" },
+ { { 6680, 8548, 8548 }, "AMC1" },
+ { { 6688, 8556, 8556 }, "AMC2" },
+ { { 6696, 8564, 8564 }, "AMS1" },
+ { { 6704, 8572, 8572 }, "AMS2" },
+ { { 6712, 8580, 8580 }, "AMP1" },
+ { { 6720, 8588, 8588 }, "AMP2" },
+ { { 6728, 8596, 8596 }, "AMB1" },
+ { { 6736, 8604, 8604 }, "AMB2" },
+ { { 6744, 8612, 8612 }, "K" },
+ { { 6748, 8616, 8616 }, "I" },
+ { { 6752, 8620, 8620 }, "L" },
+ { { 6756, 8624, 8624 }, "E" },
+ { { 6760, 8628, 8628 }, "R" },
+ { { 6764, 8632, 8632 }, "S" },
+ { { 6768, 8636, 8636 }, "PLAYPAL" },
+ { { 6776, 8644, 8644 }, "MAPE1" },
+ { { 6784, 8652, 8652 }, "MAPE2" },
+ { { 6792, 8660, 8660 }, "MAPE3" },
+ { { 6800, 8668, 8668 }, "IN_X" },
+ { { 6808, 8676, 8676 }, "IN_YAH" },
+ { { 6816, 8684, 8684 }, "FONTB16" },
+ { { 6824, 8692, 8692 }, "FONTB_S" },
+ { { 6832, 8700, 8700 }, "FONTB13" },
+ { { 6840, 8708, 8708 }, "FONTB15" },
+ { { 6848, 8716, 8716 }, "FONTB05" },
+ { { 6856, 8724, 8724 }, "FACEA0" },
+ { { 6864, 8732, 8732 }, "FACEB0" },
+ { { 6940, 8808, 8808 }, "FLOOR16" },
+ { { 6948, 8816, 8816 }, "FINISHED" },
+ { { 6960, 8828, 8828 }, "NOW ENTERING:" },
+ { { 6976, 8844, 8844 }, "KILLS" },
+ { { 6984, 8852, 8852 }, "ITEMS" },
+ { { 6992, 8860, 8860 }, "SECRETS" },
+ { { 7000, 8868, 8868 }, "TIME" },
+ { { 7008, 8876, 8876 }, "BONUS" },
+ { { 7016, 8884, 8884 }, "SECRET" },
+ { { 7024, 8892, 8892 }, "TOTAL" },
+ { { 7032, 8900, 8900 }, "VICTIMS" },
+ { { 7040, 8908, 8908 }, ":" },
+ { { 7044, 8912, 8912 }, "NEW GAME" },
+ { { 7056, 8924, 8924 }, "OPTIONS" },
+ { { 7064, 8932, 8932 }, "GAME FILES" },
+ { { 7076, 8944, 8944 }, "INFO" },
+ { { 7084, 8952, 8952 }, "QUIT GAME" },
+ { { 7096, 8964, 8964 }, "CITY OF THE DAMNED" },
+ { { 7116, 8984, 8984 }, "HELL'S MAW" },
+ { { 7128, 8996, 8996 }, "THE DOME OF D'SPARIL" },
+ { { 0, 9020, 9020 }, "THE OSSUARY" },
+ { { 0, 9032, 9032 }, "THE STAGNANT DEMESNE" },
+ { { 7152, 9056, 9056 }, "LOAD GAME" },
+ { { 7164, 9068, 9068 }, "SAVE GAME" },
+ { { 7176, 9080, 9080 }, "THOU NEEDETH A WET-NURSE" },
+ { { 7204, 9108, 9108 }, "YELLOWBELLIES-R-US" },
+ { { 7224, 9128, 9128 }, "BRINGEST THEM ONETH" },
+ { { 7244, 9148, 9148 }, "THOU ART A SMITE-MEISTER" },
+ { { 7272, 9176, 9176 }, "BLACK PLAGUE POSSESSES THEE" },
+ { { 7300, 9204, 9204 }, "END GAME" },
+ { { 7312, 9216, 9216 }, "MESSAGES : " },
+ { { 7324, 9228, 9228 }, "MOUSE SENSITIVITY" },
+ { { 7344, 9248, 9248 }, "MORE..." },
+ { { 7352, 9256, 9256 }, "SCREEN SIZE" },
+ { { 7364, 9268, 9268 }, "SFX VOLUME" },
+ { { 7376, 9280, 9280 }, "MUSIC VOLUME" },
+ { { 7416, 9296, 9296 }, "ARE YOU SURE YOU WANT TO QUIT?" },
+ { { 7448, 9328, 9328 }, "ARE YOU SURE YOU WANT TO END THE GAME?" },
+ { { 7488, 9368, 9368 }, "DO YOU WANT TO QUICKSAVE THE GAME NAMED" },
+ { { 7528, 9408, 9408 }, "DO YOU WANT TO QUICKLOAD THE GAME NAMED" },
+ { { 7392, 9448, 9448 }, "M_SKL00" },
+ { { 7400, 9456, 9456 }, "FONTA_S" },
+ { { 7408, 9464, 9464 }, "FONTB_S" },
+ { { 7568, 9472, 9472 }, "?" },
+ { { 7572, 9476, 9476 }, "M_SLCTR1" },
+ { { 7584, 9488, 9488 }, "M_SLCTR2" },
+ { { 7596, 9500, 9500 }, "M_HTIC" },
+ { { 7604, 9508, 9508 }, "c:\\heretic.cd\\hticsav%d.hsg" },
+ { { 7632, 9536, 9536 }, "hticsav%d.hsg" },
+ { { 7652, 9556, 9556 }, "M_FSLOT" },
+ { { 7660, 9564, 9564 }, "ON" },
+ { { 7664, 9568, 9568 }, "OFF" },
+ { { 0, 9572, 9572 }, "YOU CAN'T START A NEW GAME IN NETPLAY!" },
+ { { 0, 9612, 9612 }, "YOU CAN'T LOAD A GAME IN NETPLAY!" },
+ { { 7668, 9648, 9648 }, "MESSAGES ON" },
+ { { 7680, 9660, 9660 }, "MESSAGES OFF" },
+ { { 7748, 9676, 9676 }, "ONLY AVAILABLE IN THE REGISTERED VERSION" },
+ { { 7792, 9720, 9720 }, "PLAYPAL" },
+ { { 7800, 9728, 9728 }, "QUICKSAVING...." },
+ { { 7816, 9744, 9744 }, "QUICKLOADING...." },
+ { { 7836, 9764, 9764 }, "CHOOSE A QUICKSAVE SLOT" },
+ { { 7860, 9788, 9788 }, "CHOOSE A QUICKLOAD SLOT" },
+ { { 0, 9812, 9812 }, "TITLE" },
+ { { 7892, 9820, 9820 }, "M_SLDLT" },
+ { { 7900, 9828, 9828 }, "M_SLDMD1" },
+ { { 7912, 9840, 9840 }, "M_SLDMD2" },
+ { { 7924, 9852, 9852 }, "M_SLDRT" },
+ { { 7932, 9860, 9860 }, "M_SLDKB" },
+ { { 9016, 10944, 10944 }, "SCREEN SHOT" },
+ { { 9028, 10956, 10956 }, "YOU NEED A BLUE KEY TO OPEN THIS DOOR" },
+ { { 9068, 10996, 10996 }, "YOU NEED A YELLOW KEY TO OPEN THIS DOOR" },
+ { { 9108, 11036, 11036 }, "YOU NEED A GREEN KEY TO OPEN THIS DOOR" },
+ { { 9244, 11172, 11172 }, "CRYSTAL VIAL" },
+ { { 9260, 11188, 11188 }, "SILVER SHIELD" },
+ { { 9276, 11204, 11204 }, "ENCHANTED SHIELD" },
+ { { 9296, 11224, 11224 }, "BAG OF HOLDING" },
+ { { 9312, 11240, 11240 }, "MAP SCROLL" },
+ { { 9324, 11252, 11252 }, "BLUE KEY" },
+ { { 9336, 11264, 11264 }, "YELLOW KEY" },
+ { { 9348, 11276, 11276 }, "GREEN KEY" },
+ { { 9360, 11288, 11288 }, "QUARTZ FLASK" },
+ { { 9376, 11304, 11304 }, "WINGS OF WRATH" },
+ { { 9392, 11320, 11320 }, "RING OF INVINCIBILITY" },
+ { { 9416, 11344, 11344 }, "TOME OF POWER" },
+ { { 9432, 11360, 11360 }, "SHADOWSPHERE" },
+ { { 9448, 11376, 11376 }, "MORPH OVUM" },
+ { { 9460, 11388, 11388 }, "MYSTIC URN" },
+ { { 9472, 11400, 11400 }, "TORCH" },
+ { { 9480, 11408, 11408 }, "TIME BOMB OF THE ANCIENTS" },
+ { { 9508, 11436, 11436 }, "CHAOS DEVICE" },
+ { { 9524, 11452, 11452 }, "WAND CRYSTAL" },
+ { { 9540, 11468, 11468 }, "CRYSTAL GEODE" },
+ { { 9556, 11484, 11484 }, "MACE SPHERES" },
+ { { 9572, 11500, 11500 }, "PILE OF MACE SPHERES" },
+ { { 9596, 11524, 11524 }, "ETHEREAL ARROWS" },
+ { { 9612, 11540, 11540 }, "QUIVER OF ETHEREAL ARROWS" },
+ { { 9640, 11568, 11568 }, "CLAW ORB" },
+ { { 9652, 11580, 11580 }, "ENERGY ORB" },
+ { { 9664, 11592, 11592 }, "LESSER RUNES" },
+ { { 9680, 11608, 11608 }, "GREATER RUNES" },
+ { { 9696, 11624, 11624 }, "FLAME ORB" },
+ { { 9708, 11636, 11636 }, "INFERNO ORB" },
+ { { 9720, 11648, 11648 }, "FIREMACE" },
+ { { 9732, 11660, 11660 }, "ETHEREAL CROSSBOW" },
+ { { 9752, 11680, 11680 }, "DRAGON CLAW" },
+ { { 9764, 11692, 11692 }, "HELLSTAFF" },
+ { { 9776, 11704, 11704 }, "PHOENIX ROD" },
+ { { 9788, 11716, 11716 }, "GAUNTLETS OF THE NECROMANCER" },
+ { { 10088, 12016, 12016 }, "FLTWAWA1" },
+ { { 10100, 12028, 12028 }, "FLTFLWW1" },
+ { { 10112, 12040, 12040 }, "FLTLAVA1" },
+ { { 10124, 12052, 12052 }, "FLATHUH1" },
+ { { 10136, 12064, 12064 }, "FLTSLUD1" },
+ { { 10148, 12076, 12076 }, "END" },
+ { { 10236, 12164, 12164 }, "texture2" },
+ { { 10444, 12372, 12372 }, "PLAYPAL" },
+ { { 10596, 12488, 12488 }, "PNAMES" },
+ { { 10604, 12496, 12496 }, "TEXTURE1" },
+ { { 10616, 12508, 12508 }, "TEXTURE2" },
+ { { 10628, 12520, 12520 }, "S_END" },
+ { { 10636, 12528, 12528 }, "S_START" },
+ { { 10728, 12620, 12620 }, "F_START" },
+ { { 10736, 12628, 12628 }, "F_END" },
+ { { 10744, 12636, 12636 }, "COLORMAP" },
+ { { 10756, 12648, 12648 }, "\nR_InitTextures " },
+ { { 10776, 12668, 12668 }, "R_InitFlats\n" },
+ { { 10792, 12684, 12684 }, "R_InitSpriteLumps " },
+ { { 10948, 12772, 12772 }, "TINTTAB" },
+ { { 10984, 12780, 12780 }, "FLOOR04" },
+ { { 10992, 12788, 12788 }, "FLAT513" },
+ { { 11000, 12796, 12796 }, "bordt" },
+ { { 11008, 12804, 12804 }, "bordb" },
+ { { 11016, 12812, 12812 }, "bordl" },
+ { { 11024, 12820, 12820 }, "bordr" },
+ { { 11032, 12828, 12828 }, "bordtl" },
+ { { 11040, 12836, 12836 }, "bordtr" },
+ { { 11048, 12844, 12844 }, "bordbr" },
+ { { 11056, 12852, 12852 }, "bordbl" },
+ { { 11064, 12860, 12860 }, "R_InitData " },
+ { { 11076, 12872, 12872 }, "R_InitPointToAngle\n" },
+ { { 11096, 12892, 12892 }, "R_InitTables " },
+ { { 11112, 12908, 12908 }, "R_InitPlanes\n" },
+ { { 11128, 12924, 12924 }, "R_InitLightTables " },
+ { { 11148, 12944, 12944 }, "R_InitSkyMap\n" },
+ { { 11164, 12960, 12960 }, "F_SKY1" },
+ { { 12120, 13484, 13484 }, "LTFACE" },
+ { { 12128, 13492, 13492 }, "RTFACE" },
+ { { 12136, 13500, 13500 }, "BARBACK" },
+ { { 12144, 13508, 13508 }, "INVBAR" },
+ { { 12152, 13516, 13516 }, "CHAIN" },
+ { { 12160, 13524, 13524 }, "STATBAR" },
+ { { 12168, 13532, 13532 }, "LIFEBAR" },
+ { { 12176, 13540, 13540 }, "LIFEGEM2" },
+ { { 12188, 13552, 13552 }, "LIFEGEM0" },
+ { { 12200, 13564, 13564 }, "LTFCTOP" },
+ { { 12208, 13572, 13572 }, "RTFCTOP" },
+ { { 12224, 13580, 13580 }, "SELECTBOX" },
+ { { 12236, 13592, 13592 }, "INVGEML1" },
+ { { 12248, 13604, 13604 }, "INVGEML2" },
+ { { 12260, 13616, 13616 }, "INVGEMR1" },
+ { { 12272, 13628, 13628 }, "INVGEMR2" },
+ { { 12284, 13640, 13640 }, "BLACKSQ" },
+ { { 12292, 13648, 13648 }, "ARMCLEAR" },
+ { { 12304, 13660, 13660 }, "CHAINBACK" },
+ { { 12316, 13672, 13672 }, "IN0" },
+ { { 12320, 13676, 13676 }, "NEGNUM" },
+ { { 12328, 13684, 13684 }, "FONTB16" },
+ { { 12336, 13692, 13692 }, "SMALLIN0" },
+ { { 12348, 13704, 13704 }, "PLAYPAL" },
+ { { 12356, 13712, 13712 }, "SPINBK0" },
+ { { 12364, 13720, 13720 }, "SPFLY0" },
+ { { 12372, 13728, 13728 }, "LAME" },
+ { { 12380, 13736, 13736 }, "*** SOUND DEBUG INFO ***" },
+ { { 12408, 13764, 13764 }, "NAME" },
+ { { 12416, 13772, 13772 }, "MO.T" },
+ { { 12424, 13780, 13780 }, "MO.X" },
+ { { 12432, 13788, 13788 }, "MO.Y" },
+ { { 12440, 13796, 13796 }, "ID" },
+ { { 12444, 13800, 13800 }, "PRI" },
+ { { 12448, 13804, 13804 }, "DIST" },
+ { { 12456, 13812, 13812 }, "------" },
+ { { 12464, 13820, 13820 }, "%s" },
+ { { 12468, 13824, 13824 }, "%d" },
+ { { 12472, 13828, 13828 }, "GOD1" },
+ { { 12480, 13836, 13836 }, "GOD2" },
+ { { 12488, 13844, 13844 }, "useartia" },
+ { { 12500, 13856, 13856 }, "ykeyicon" },
+ { { 12512, 13868, 13868 }, "gkeyicon" },
+ { { 12524, 13880, 13880 }, "bkeyicon" },
+ { { 12216, 13892, 13892 }, "ARTIBOX" },
+ { { 12536, 13900, 13900 }, "GOD MODE ON" },
+ { { 12548, 13912, 13912 }, "GOD MODE OFF" },
+ { { 12564, 13928, 13928 }, "NO CLIPPING ON" },
+ { { 12580, 13944, 13944 }, "NO CLIPPING OFF" },
+ { { 12596, 13960, 13960 }, "ALL WEAPONS" },
+ { { 12608, 13972, 13972 }, "POWER OFF" },
+ { { 12620, 13984, 13984 }, "POWER ON" },
+ { { 12632, 13996, 13996 }, "FULL HEALTH" },
+ { { 12644, 14008, 14008 }, "ALL KEYS" },
+ { { 12656, 14020, 14020 }, "SOUND DEBUG ON" },
+ { { 12672, 14036, 14036 }, "SOUND DEBUG OFF" },
+ { { 12688, 14052, 14052 }, "TICKER ON" },
+ { { 12700, 14064, 14064 }, "TICKER OFF" },
+ { { 12712, 14076, 14076 }, "CHOOSE AN ARTIFACT ( A - J )" },
+ { { 12744, 14108, 14108 }, "HOW MANY ( 1 - 9 )" },
+ { { 12764, 14128, 14128 }, "YOU GOT IT" },
+ { { 12776, 14140, 14140 }, "BAD INPUT" },
+ { { 12788, 14152, 14152 }, "LEVEL WARP" },
+ { { 12800, 14164, 14164 }, "CHICKEN OFF" },
+ { { 12812, 14176, 14176 }, "CHICKEN ON" },
+ { { 12824, 14188, 14188 }, "MASSACRE" },
+ { { 12836, 14200, 14200 }, "CHEATER - YOU DON'T DESERVE WEAPONS" },
+ { { 12872, 14236, 14236 }, "TRYING TO CHEAT, EH? NOW YOU DIE!" },
+};
+
+// String offsets that are valid but we don't support.
+
+static const int unsupported_strings_1_0[] =
+{
+ 0, 4, 64, 104, 160, 200, 220, 236,
+ 244, 252, 272, 288, 296, 316, 332, 372,
+ 436, 500, 504, 536, 544, 560, 576, 584,
+ 592, 612, 640, 664, 708, 712, 744, 764,
+ 808, 820, 828, 840, 876, 884, 908, 952,
+ 992, 1028, 1036, 1048, 1088, 1128, 1160, 1192,
+ 1212, 1912, 2044, 2056, 2068, 2128, 2140, 2168,
+ 2184, 2196, 2212, 2228, 2240, 2252, 2260, 2264,
+ 2284, 2292, 2296, 2300, 2328, 2340, 2352, 2364,
+ 2372, 2384, 2388, 2404, 2428, 2436, 2444, 2464,
+ 2496, 2508, 2520, 2552, 2564, 2572, 2584, 3120,
+ 3128, 3140, 3184, 3220, 3248, 3252, 3256, 3280,
+ 3304, 3320, 3352, 3380, 3400, 3432, 3464, 3548,
+ 3600, 3624, 3664, 3696, 3812, 3872, 3932, 3940,
+ 3976, 3996, 6872, 6896, 7648, 7696, 7940, 7964,
+ 7968, 7992, 8020, 8028, 8052, 8056, 8076, 8088,
+ 8104, 8116, 8128, 8136, 8148, 8164, 8180, 8192,
+ 8204, 8220, 8232, 8248, 8264, 8276, 8292, 8308,
+ 8320, 8328, 8340, 8352, 8364, 8376, 8392, 8408,
+ 8424, 8436, 8448, 8460, 8472, 8488, 8504, 8520,
+ 8536, 8548, 8560, 8572, 8584, 8596, 8608, 8612,
+ 8624, 8648, 8660, 8668, 8680, 8708, 8720, 8728,
+ 8740, 8752, 8764, 8788, 8800, 8812, 8824, 8848,
+ 8860, 8864, 8868, 8876, 8888, 8896, 8916, 8944,
+ 8948, 8960, 8964, 8968, 8980, 9148, 9172, 9212,
+ 9216, 9220, 9820, 9860, 9892, 9940, 9972, 10012,
+ 10036, 10040, 10052, 10080, 10152, 10192, 10248, 10284,
+ 10320, 10360, 10392, 10452, 10488, 10508, 10556, 10644,
+ 10684, 10812, 10844, 10880, 10912, 10956, 11172, 11200,
+ 11232, 11272, 11312, 11348, 11380, 11404, 11436, 11492,
+ 11548, 11616, 11684, 11748, 11792, 11840, 11896, 11936,
+ 11980, 12028, 12072, 12908, 12924, 12956, 12960, 12968,
+ 12976, 13020, 13048, 13076, 13104, 13136, 13168, 13196,
+ 13240, 13272, 13292, 13296, 13308, 13312, 13320, 13324,
+ 13364, 13408, 13460, 13492, 13516, 13560, 13612, 13664,
+ 13700, 13744, 13796, 13848, 13884, 13940, 13996, 14040,
+ 14084, 14140, 14148, 14156, 14164, 14184, 14192, 14204,
+ 14208, 14212, 14256, 14272, 14284, 14296, 14300, 14312,
+ 14320, 14324, 14348, 14356, 14360, 14372, 14380, 14392,
+ 14432, 14440, 14444, 14472, 14496, 14516, 14536, 14548,
+ 14560, 14572, 14580, 14588, 14596, 14604, 14612, 14620,
+ 14636, 14660, 14704, 14740, 14748, 14756, 14760, 14768,
+ -1,
+};
+
+static const int unsupported_strings_1_2[] =
+{
+ 0, 4, 64, 104, 160, 200, 220, 236,
+ 244, 252, 272, 288, 296, 316, 332, 372,
+ 436, 500, 504, 536, 544, 560, 576, 584,
+ 592, 612, 640, 664, 708, 712, 744, 756,
+ 776, 820, 832, 840, 852, 888, 896, 920,
+ 964, 1004, 1040, 1048, 1060, 1100, 1140, 1172,
+ 1204, 1224, 2312, 2436, 2448, 2464, 2480, 2492,
+ 2512, 2524, 2536, 2596, 2608, 2636, 2652, 2656,
+ 2676, 2684, 2688, 2720, 2732, 2744, 2752, 2764,
+ 2772, 2776, 2792, 2816, 2824, 2832, 2852, 2884,
+ 2896, 2908, 2940, 2952, 2960, 2972, 3520, 3528,
+ 3540, 3584, 3620, 3648, 3652, 3656, 3680, 3704,
+ 3720, 3776, 3804, 3824, 3856, 3888, 4020, 4044,
+ 4084, 4116, 4156, 4272, 4288, 4296, 4332, 4352,
+ 4428, 4432, 8740, 8764, 9552, 9868, 9888, 9900,
+ 9916, 9928, 9940, 9948, 9960, 9976, 9992, 10004,
+ 10016, 10032, 10044, 10060, 10076, 10088, 10104, 10120,
+ 10132, 10140, 10152, 10164, 10176, 10188, 10204, 10220,
+ 10236, 10248, 10260, 10272, 10284, 10300, 10316, 10332,
+ 10348, 10360, 10372, 10384, 10396, 10408, 10420, 10424,
+ 10436, 10460, 10472, 10480, 10492, 10520, 10532, 10540,
+ 10552, 10564, 10576, 10600, 10612, 10624, 10636, 10660,
+ 10672, 10676, 10700, 10704, 10728, 10756, 10764, 10788,
+ 10792, 10796, 10804, 10816, 10824, 10844, 10872, 10876,
+ 10888, 10892, 10896, 10908, 11076, 11100, 11140, 11144,
+ 11148, 11748, 11788, 11820, 11868, 11900, 11940, 11964,
+ 11968, 11980, 12008, 12080, 12120, 12176, 12212, 12248,
+ 12288, 12320, 12380, 12400, 12448, 12536, 12576, 12704,
+ 12736, 12968, 13000, 13024, 13080, 13136, 13204, 13272,
+ 13336, 13380, 13428, 14272, 14288, 14320, 14324, 14332,
+ 14340, 14384, 14412, 14440, 14468, 14500, 14532, 14560,
+ 14604, 14636, 14656, 14696, 14740, 14792, 14824, 14848,
+ 14892, 14944, 14996, 15032, 15076, 15128, 15180, 15216,
+ 15272, 15328, 15372, 15416, 15472, 15480, 15488, 15496,
+ 15516, 15524, 15536, 15540, 15544, 15588, 15604, 15616,
+ 15628, 15632, 15644, 15652, 15656, 15680, 15688, 15692,
+ 15704, 15712, 15724, 15764, 15772, 15776, 15804, 15828,
+ 15848, 15868, 15880, 15892, 15904, 15912, 15920, 15928,
+ 15936, -1,
+};
+
+static const int unsupported_strings_1_3[] =
+{
+ 0, 4, 64, 104, 160, 200, 220, 236,
+ 244, 252, 272, 288, 296, 316, 332, 372,
+ 436, 500, 504, 536, 544, 560, 576, 584,
+ 592, 612, 640, 664, 708, 712, 744, 756,
+ 776, 820, 832, 840, 852, 888, 896, 920,
+ 964, 1004, 1040, 1048, 1060, 1100, 1140, 1172,
+ 1204, 1224, 2312, 2436, 2448, 2464, 2480, 2492,
+ 2512, 2524, 2536, 2596, 2608, 2636, 2652, 2656,
+ 2676, 2684, 2688, 2720, 2732, 2744, 2752, 2764,
+ 2772, 2776, 2792, 2816, 2824, 2832, 2852, 2884,
+ 2896, 2908, 2940, 2952, 2960, 2972, 3520, 3528,
+ 3540, 3584, 3620, 3648, 3652, 3656, 3680, 3704,
+ 3720, 3776, 3804, 3824, 3856, 3888, 4020, 4044,
+ 4084, 4116, 4156, 4272, 4288, 4296, 4332, 4352,
+ 4428, 4432, 8740, 8764, 9552, 9868, 9888, 9900,
+ 9916, 9928, 9940, 9948, 9960, 9976, 9992, 10004,
+ 10016, 10032, 10044, 10060, 10076, 10088, 10104, 10120,
+ 10132, 10140, 10152, 10164, 10176, 10188, 10204, 10220,
+ 10236, 10248, 10260, 10272, 10284, 10300, 10316, 10332,
+ 10348, 10360, 10372, 10384, 10396, 10408, 10420, 10424,
+ 10436, 10460, 10472, 10480, 10492, 10520, 10532, 10540,
+ 10552, 10564, 10576, 10600, 10612, 10624, 10636, 10660,
+ 10672, 10676, 10700, 10704, 10728, 10756, 10764, 10788,
+ 10792, 10796, 10804, 10816, 10824, 10844, 10872, 10876,
+ 10888, 10892, 10896, 10908, 11076, 11100, 11140, 11144,
+ 11148, 11748, 11788, 11820, 11868, 11900, 11940, 11964,
+ 11968, 11980, 12008, 12080, 12120, 12176, 12212, 12248,
+ 12288, 12320, 12380, 12400, 12448, 12536, 12576, 12704,
+ 12736, 12968, 13000, 13024, 13080, 13136, 13204, 13272,
+ 13336, 13380, 13428, 14272, 14288, 14320, 14324, 14332,
+ 14340, 14384, 14412, 14440, 14468, 14500, 14532, 14560,
+ 14604, 14636, 14656, 14696, 14740, 14792, 14824, 14848,
+ 14892, 14944, 14996, 15032, 15076, 15128, 15180, 15216,
+ 15272, 15328, 15372, 15416, 15472, 15480, 15488, 15496,
+ 15516, 15524, 15536, 15540, 15544, 15588, 15604, 15616,
+ 15628, 15632, 15644, 15652, 15656, 15680, 15688, 15692,
+ 15704, 15712, 15724, 15764, 15772, 15776, 15804, 15828,
+ 15848, 15868, 15880, 15892, 15904, 15912, 15920, 15928,
+ 15936, -1,
+};
+
+static const int *unsupported_strings[] =
+{
+ unsupported_strings_1_0,
+ unsupported_strings_1_2,
+ unsupported_strings_1_3,
+};
+
+static boolean StringIsUnsupported(unsigned int offset)
+{
+ const int *string_list;
+ int i;
+
+ string_list = unsupported_strings[deh_hhe_version];
+
+ for (i=0; string_list[i] >= 0; ++i)
+ {
+ if ((unsigned int) string_list[i] == offset)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static boolean GetStringByOffset(unsigned int offset, char **result)
+{
+ int i;
+
+ for (i=0; i<arrlen(strings); ++i)
+ {
+ if (strings[i].offsets[deh_hhe_version] == offset)
+ {
+ *result = strings[i].string;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Given a string length, find the maximum length of a
+// string that can replace it.
+
+static int MaxStringLength(int len)
+{
+ // Enough bytes for the string and the NUL terminator
+
+ len += 1;
+
+ // All strings in doom.exe are on 4-byte boundaries, so we may be able
+ // to support a slightly longer string.
+ // Extend up to the next 4-byte boundary
+
+ len += (4 - (len % 4)) % 4;
+
+ // Less one for the NUL terminator.
+
+ return len - 1;
+}
+
+// If a string offset does not match any string, it may be because
+// we are running in the wrong version mode, and the patch was generated
+// for a different Heretic version. Search the lookup tables to find
+// versiosn that match.
+
+static void SuggestOtherVersions(unsigned int offset)
+{
+ const int *string_list;
+ unsigned int i;
+ unsigned int v;
+
+ // Check main string table.
+
+ for (i=0; i<arrlen(strings); ++i)
+ {
+ for (v=0; v<deh_hhe_num_versions; ++v)
+ {
+ if (strings[i].offsets[v] == offset)
+ {
+ DEH_SuggestHereticVersion(v);
+ }
+ }
+ }
+
+ // Check unsupported string tables.
+
+ for (v=0; v<deh_hhe_num_versions; ++v)
+ {
+ string_list = unsupported_strings[v];
+
+ for (i=0; string_list[i] >= 0; ++i)
+ {
+ if (string_list[i] == offset)
+ {
+ DEH_SuggestHereticVersion(v);
+ }
+ }
+ }
+}
+
+static void *DEH_TextStart(deh_context_t *context, char *line)
+{
+ char *repl_text;
+ char *orig_text;
+ int orig_offset, repl_len;
+ int i;
+
+ if (sscanf(line, "Text %i %i", &orig_offset, &repl_len) != 2)
+ {
+ DEH_Warning(context, "Parse error on section start");
+ return NULL;
+ }
+
+ repl_text = Z_Malloc(repl_len + 1, PU_STATIC, NULL);
+
+ // read in the "to" text
+
+ for (i=0; i<repl_len; ++i)
+ {
+ int c;
+
+ c = DEH_GetChar(context);
+
+ repl_text[i] = c;
+ }
+ repl_text[repl_len] = '\0';
+
+ // We don't support all strings, but at least recognise them:
+
+ if (StringIsUnsupported(orig_offset))
+ {
+ DEH_Warning(context, "Unsupported string replacement: %i", orig_offset);
+ }
+
+ // Find the string to replace:
+
+ else if (!GetStringByOffset(orig_offset, &orig_text))
+ {
+ SuggestOtherVersions(orig_offset);
+ DEH_Error(context, "Unknown string offset: %i", orig_offset);
+ }
+
+ // Only allow string replacements that are possible in Vanilla Doom.
+ // Chocolate Doom is unforgiving!
+
+ else if (!deh_allow_long_strings
+ && repl_len > MaxStringLength(strlen(orig_text)))
+ {
+ DEH_Error(context, "Replacement string is longer than the maximum "
+ "possible in heretic.exe");
+ }
+ else
+ {
+ // Success.
+
+ DEH_AddStringReplacement(orig_text, repl_text);
+
+ return NULL;
+ }
+
+ // Failure.
+
+ Z_Free(repl_text);
+
+ return NULL;
+}
+
+static void DEH_TextParseLine(deh_context_t *context, char *line, void *tag)
+{
+ // not used
+}
+
+deh_section_t deh_section_heretic_text =
+{
+ "Text",
+ NULL,
+ DEH_TextStart,
+ DEH_TextParseLine,
+ NULL,
+ NULL,
+};
+
diff --git a/src/heretic/deh_htic.c b/src/heretic/deh_htic.c
new file mode 100644
index 00000000..440fde96
--- /dev/null
+++ b/src/heretic/deh_htic.c
@@ -0,0 +1,186 @@
+// 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 Heretic dehacked (HHE).
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_htic.h"
+#include "info.h"
+#include "m_argv.h"
+
+char *deh_signatures[] =
+{
+ "Patch File for HHE v1.0",
+ "Patch File for HHE v1.1",
+ NULL
+};
+
+static char *hhe_versions[] =
+{
+ "1.0", "1.2", "1.3"
+};
+
+// Version number for patches.
+
+deh_hhe_version_t deh_hhe_version = deh_hhe_1_0;
+
+// deh_ammo.c:
+extern deh_section_t deh_section_ammo;
+// deh_frame.c:
+extern deh_section_t deh_section_frame;
+// deh_ptr.c:
+extern deh_section_t deh_section_pointer;
+// deh_sound.c
+extern deh_section_t deh_section_sound;
+// deh_htext.c:
+extern deh_section_t deh_section_heretic_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_frame,
+// &deh_section_pointer, TODO
+ &deh_section_sound,
+ &deh_section_heretic_text,
+ &deh_section_thing,
+ &deh_section_weapon,
+ NULL
+};
+
+static void SetHHEVersionByName(char *name)
+{
+ int i;
+
+ for (i=0; i<arrlen(hhe_versions); ++i)
+ {
+ if (!strcmp(hhe_versions[i], name))
+ {
+ deh_hhe_version = i;
+ return;
+ }
+ }
+
+ fprintf(stderr, "Unknown Heretic version: %s\n", name);
+ fprintf(stderr, "Valid versions:\n");
+
+ for (i=0; i<arrlen(hhe_versions); ++i)
+ {
+ fprintf(stderr, "\t%s\n", hhe_versions[i]);
+ }
+}
+
+// Initialize Heretic(HHE)-specific dehacked bits.
+
+void DEH_HereticInit(void)
+{
+ int i;
+
+ //!
+ // @arg <version>
+ //
+ // Select the Heretic version number that was used to generate the
+ // HHE patch to be loaded. Patches for each of the Vanilla
+ // Heretic versions (1.0, 1.2, 1.3) can be loaded, but the correct
+ // version number must be specified.
+
+ i = M_CheckParm("-hhever");
+
+ if (i > 0)
+ {
+ SetHHEVersionByName(myargv[i + 1]);
+ }
+
+ // For v1.0 patches, we must apply a slight change to the states[]
+ // table. The table was changed between 1.0 and 1.3 to add two extra
+ // frames to the player "burning death" animation.
+ //
+ // If we are using a v1.0 patch, we must change the table to cut
+ // these out again.
+
+ if (deh_hhe_version < deh_hhe_1_2)
+ {
+ states[S_PLAY_FDTH18].nextstate = S_NULL;
+ }
+}
+
+int DEH_MapHereticFrameNumber(int frame)
+{
+ if (deh_hhe_version < deh_hhe_1_2)
+ {
+ // Between Heretic 1.0 and 1.2, two new frames
+ // were added to the "states" table, to extend the "flame death"
+ // animation displayed when the player is killed by fire. Therefore,
+ // we must map Heretic 1.0 frame numbers to corresponding indexes
+ // for our state table.
+
+ if (frame >= S_PLAY_FDTH19)
+ {
+ frame = (frame - S_PLAY_FDTH19) + S_BLOODYSKULL1;
+ }
+ }
+ else
+ {
+ // After Heretic 1.2, three unused frames were removed from the
+ // states table, unused phoenix rod frames. Our state table includes
+ // these missing states for backwards compatibility. We must therefore
+ // adjust frame numbers for v1.2/v1.3 to corresponding indexes for
+ // our state table.
+
+ if (frame >= S_PHOENIXFXIX_1)
+ {
+ frame = (frame - S_PHOENIXFXIX_1) + S_PHOENIXPUFF1;
+ }
+ }
+
+ return frame;
+}
+
+void DEH_SuggestHereticVersion(deh_hhe_version_t version)
+{
+ fprintf(stderr,
+ "\n"
+ "This patch may be for version %s. You are currently running in\n"
+ "Heretic %s mode. For %s mode, this mode, add this to your command line:\n"
+ "\n"
+ "\t-hhever %s\n"
+ "\n",
+ hhe_versions[version],
+ hhe_versions[deh_hhe_version],
+ hhe_versions[version],
+ hhe_versions[version]);
+}
+
diff --git a/src/heretic/deh_htic.h b/src/heretic/deh_htic.h
new file mode 100644
index 00000000..7855da8c
--- /dev/null
+++ b/src/heretic/deh_htic.h
@@ -0,0 +1,60 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2010 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.
+//
+//-----------------------------------------------------------------------------
+//
+// Common header for Heretic dehacked (HHE) support.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef DEH_HTIC_H
+#define DEH_HTIC_H
+
+#include "info.h"
+
+// HHE executable version. Loading HHE patches is (unfortunately)
+// dependent on the version of the Heretic executable used to make them.
+
+typedef enum
+{
+ deh_hhe_1_0,
+ deh_hhe_1_2,
+ deh_hhe_1_3,
+ deh_hhe_num_versions
+} deh_hhe_version_t;
+
+// HHE doesn't know about the last two states in the state table, so
+// these are considered invalid.
+
+#define DEH_HERETIC_NUMSTATES (NUMSTATES - 2)
+
+// It also doesn't know about the last two things in the mobjinfo table
+// (which correspond to the states above)
+
+#define DEH_HERETIC_NUMMOBJTYPES (NUMMOBJTYPES - 2)
+
+void DEH_HereticInit(void);
+int DEH_MapHereticFrameNumber(int frame);
+void DEH_SuggestHereticVersion(deh_hhe_version_t version);
+
+extern deh_hhe_version_t deh_hhe_version;
+
+#endif /* #ifndef DEH_HTIC_H */
+
diff --git a/src/heretic/deh_sound.c b/src/heretic/deh_sound.c
new file mode 100644
index 00000000..d1f266dd
--- /dev/null
+++ b/src/heretic/deh_sound.c
@@ -0,0 +1,118 @@
+// 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 "doomdef.h"
+#include "i_sound.h"
+
+#include "sounds.h"
+
+DEH_BEGIN_MAPPING(sound_mapping, sfxinfo_t)
+ DEH_MAPPING_STRING("Name", name)
+ DEH_UNSUPPORTED_MAPPING("Special")
+ DEH_MAPPING("Value", priority)
+ DEH_MAPPING("Unknown 1", usefulness)
+ DEH_UNSUPPORTED_MAPPING("Unknown 2")
+ DEH_UNSUPPORTED_MAPPING("Unknown 3")
+ DEH_MAPPING("One/Two", numchannels)
+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;
+
+ 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;
+ }
+
+ // Set the field value:
+
+ if (!strcasecmp(variable_name, "Name"))
+ {
+ DEH_SetStringMapping(context, &sound_mapping, sfx,
+ variable_name, value);
+ }
+ else
+ {
+ DEH_SetMapping(context, &sound_mapping, sfx,
+ variable_name, atoi(value));
+ }
+}
+
+deh_section_t deh_section_sound =
+{
+ "Sound",
+ NULL,
+ DEH_SoundStart,
+ DEH_SoundParseLine,
+ NULL,
+ NULL,
+};
+
diff --git a/src/heretic/deh_thing.c b/src/heretic/deh_thing.c
new file mode 100644
index 00000000..ffededf2
--- /dev/null
+++ b/src/heretic/deh_thing.c
@@ -0,0 +1,150 @@
+// 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 "m_misc.h"
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+#include "deh_htic.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("Burning 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 1", flags)
+ DEH_MAPPING("Bits 2", flags2)
+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;
+ }
+
+ // HHE thing numbers are indexed from 1
+ --thing_number;
+
+ if (thing_number < 0 || thing_number >= DEH_HERETIC_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;
+ }
+
+ // all values are integers
+
+ ivalue = atoi(value);
+
+ // If the value to be set is a frame, the frame number must
+ // undergo transformation from a Heretic 1.0 index to a
+ // Heretic 1.3 index.
+
+ if (M_StrCaseStr(variable_name, "frame") != NULL)
+ {
+ ivalue = DEH_MapHereticFrameNumber(ivalue);
+ }
+
+ // 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/heretic/deh_weapon.c b/src/heretic/deh_weapon.c
new file mode 100644
index 00000000..28a90c68
--- /dev/null
+++ b/src/heretic/deh_weapon.c
@@ -0,0 +1,131 @@
+// 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 "m_misc.h"
+
+#include "doomdef.h"
+
+#include "deh_defs.h"
+#include "deh_main.h"
+#include "deh_mapping.h"
+#include "deh_htic.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", holdatkstate)
+ DEH_MAPPING("Unknown frame", flashstate)
+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 * 2)
+ {
+ DEH_Warning(context, "Invalid weapon number: %i", weapon_number);
+ return NULL;
+ }
+
+ // Because of the tome of power, we have two levels of weapons:
+
+ if (weapon_number < NUMWEAPONS)
+ {
+ return &wpnlev1info[weapon_number];
+ }
+ else
+ {
+ return &wpnlev2info[weapon_number - NUMWEAPONS];
+ }
+}
+
+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);
+
+ // If this is a frame field, we need to map from Heretic 1.0 frame
+ // numbers to Heretic 1.3 frame numbers.
+
+ if (M_StrCaseStr(variable_name, "frame") != NULL)
+ {
+ ivalue = DEH_MapHereticFrameNumber(ivalue);
+ }
+
+ 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, &wpnlev1info[i]);
+ DEH_StructMD5Sum(context, &weapon_mapping, &wpnlev2info[i]);
+ }
+}
+
+deh_section_t deh_section_weapon =
+{
+ "Weapon",
+ NULL,
+ DEH_WeaponStart,
+ DEH_WeaponParseLine,
+ NULL,
+ DEH_WeaponMD5Sum,
+};
+
diff --git a/src/heretic/doomdef.h b/src/heretic/doomdef.h
index 3f976c3d..aa1d0c0d 100644
--- a/src/heretic/doomdef.h
+++ b/src/heretic/doomdef.h
@@ -581,6 +581,7 @@ extern boolean singletics; // debug flag to cancel adaptiveness
extern boolean DebugSound; // debug flag for displaying sound info
extern int maxammo[NUMAMMO];
+extern int GetWeaponAmmo[NUMWEAPONS];
extern boolean demoplayback;
extern int skytexture;
diff --git a/src/heretic/dstrings.h b/src/heretic/dstrings.h
index aea5548e..93900f9d 100644
--- a/src/heretic/dstrings.h
+++ b/src/heretic/dstrings.h
@@ -26,42 +26,6 @@
//---------------------------------------------------------------------------
//
-// M_menu.c
-//
-//---------------------------------------------------------------------------
-#define PRESSKEY "press a key."
-#define PRESSYN "press y or n."
-#define TXT_PAUSED "PAUSED"
-#define QUITMSG "are you sure you want to\nquit this great game?"
-#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY
-#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY
-#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY
-#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY
-#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN
-#define QLPROMPT "do you want to quickload the game named"\
- "\n\n'%s'?\n\n"PRESSYN
-#define NEWGAME "you can't start a new game\n"\
- "while in a network game.\n\n"PRESSKEY
-#define NIGHTMARE "are you sure? this skill level\n"\
- "isn't even remotely fair.\n\n"PRESSYN
-#define SWSTRING "this is the shareware version of doom.\n\n"\
- "you need to order the entire trilogy.\n\n"PRESSKEY
-#define MSGOFF "Messages OFF"
-#define MSGON "Messages ON"
-#define NETEND "you can't end a netgame!\n\n"PRESSKEY
-#define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN
-#define DOSY "(press y to quit to dos.)"
-#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
//
//---------------------------------------------------------------------------
@@ -170,74 +134,6 @@
//---------------------------------------------------------------------------
//
-// HU_stuff.c
-//
-//---------------------------------------------------------------------------
-
-#define HUSTR_E1M1 "E1M1: Hangar"
-#define HUSTR_E1M2 "E1M2: Nuclear Plant"
-#define HUSTR_E1M3 "E1M3: Toxin Refinery"
-#define HUSTR_E1M4 "E1M4: Command Control"
-#define HUSTR_E1M5 "E1M5: Phobos Lab"
-#define HUSTR_E1M6 "E1M6: Central Processing"
-#define HUSTR_E1M7 "E1M7: Computer Station"
-#define HUSTR_E1M8 "E1M8: Phobos Anomaly"
-#define HUSTR_E1M9 "E1M9: Military Base"
-
-#define HUSTR_E2M1 "E2M1: Deimos Anomaly"
-#define HUSTR_E2M2 "E2M2: Containment Area"
-#define HUSTR_E2M3 "E2M3: Refinery"
-#define HUSTR_E2M4 "E2M4: Deimos Lab"
-#define HUSTR_E2M5 "E2M5: Command Center"
-#define HUSTR_E2M6 "E2M6: Halls of the Damned"
-#define HUSTR_E2M7 "E2M7: Spawning Vats"
-#define HUSTR_E2M8 "E2M8: Tower of Babel"
-#define HUSTR_E2M9 "E2M9: Fortress of Mystery"
-
-#define HUSTR_E3M1 "E3M1: Hell Keep"
-#define HUSTR_E3M2 "E3M2: Slough of Despair"
-#define HUSTR_E3M3 "E3M3: Pandemonium"
-#define HUSTR_E3M4 "E3M4: House of Pain"
-#define HUSTR_E3M5 "E3M5: Unholy Cathedral"
-#define HUSTR_E3M6 "E3M6: Mt. Erebus"
-#define HUSTR_E3M7 "E3M7: Limbo"
-#define HUSTR_E3M8 "E3M8: Dis"
-#define HUSTR_E3M9 "E3M9: Warrens"
-
-#define HUSTR_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
//
//---------------------------------------------------------------------------
@@ -253,26 +149,6 @@
//---------------------------------------------------------------------------
//
-// ST_stuff.c
-//
-//---------------------------------------------------------------------------
-
-#define STSTR_DQDON "Degreelessness Mode On"
-#define STSTR_DQDOFF "Degreelessness Mode Off"
-
-#define STSTR_KFAADDED "Very Happy Ammo 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
//
//---------------------------------------------------------------------------
@@ -374,56 +250,3 @@
"surrender without a fight. eyes\n"\
"wide, you go to meet your fate."
-/*
-#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 ..."
-*/
diff --git a/src/heretic/f_finale.c b/src/heretic/f_finale.c
index 03806214..4077bb82 100644
--- a/src/heretic/f_finale.c
+++ b/src/heretic/f_finale.c
@@ -26,6 +26,7 @@
#include <ctype.h>
#include "doomdef.h"
+#include "deh_str.h"
#include "i_swap.h"
#include "i_video.h"
#include "s_sound.h"
@@ -37,11 +38,6 @@ int finalecount;
#define TEXTSPEED 3
#define TEXTWAIT 250
-char *e1text = E1TEXT;
-char *e2text = E2TEXT;
-char *e3text = E3TEXT;
-char *e4text = E4TEXT;
-char *e5text = E5TEXT;
char *finaletext;
char *finaleflat;
@@ -72,30 +68,30 @@ void F_StartFinale(void)
switch (gameepisode)
{
case 1:
- finaleflat = "FLOOR25";
- finaletext = e1text;
+ finaleflat = DEH_String("FLOOR25");
+ finaletext = DEH_String(E1TEXT);
break;
case 2:
- finaleflat = "FLATHUH1";
- finaletext = e2text;
+ finaleflat = DEH_String("FLATHUH1");
+ finaletext = DEH_String(E2TEXT);
break;
case 3:
- finaleflat = "FLTWAWA2";
- finaletext = e3text;
+ finaleflat = DEH_String("FLTWAWA2");
+ finaletext = DEH_String(E3TEXT);
break;
case 4:
- finaleflat = "FLOOR28";
- finaletext = e4text;
+ finaleflat = DEH_String("FLOOR28");
+ finaletext = DEH_String(E4TEXT);
break;
case 5:
- finaleflat = "FLOOR08";
- finaletext = e5text;
+ finaleflat = DEH_String("FLOOR08");
+ finaletext = DEH_String(E5TEXT);
break;
}
finalestage = 0;
finalecount = 0;
- FontABaseLump = W_GetNumForName("FONTA_S") + 1;
+ FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1;
// S_ChangeMusic(mus_victor, true);
S_StartSong(mus_cptd, true);
@@ -277,8 +273,8 @@ void F_DemonScroll(void)
{
return;
}
- p1 = W_CacheLumpName("FINAL1", PU_LEVEL);
- p2 = W_CacheLumpName("FINAL2", PU_LEVEL);
+ p1 = W_CacheLumpName(DEH_String("FINAL1"), PU_LEVEL);
+ p2 = W_CacheLumpName(DEH_String("FINAL2"), PU_LEVEL);
if (finalecount < 70)
{
memcpy(I_VideoBuffer, p1, SCREENHEIGHT * SCREENWIDTH);
@@ -319,8 +315,8 @@ void F_DrawUnderwater(void)
{
underwawa = true;
memset((byte *) 0xa0000, 0, SCREENWIDTH * SCREENHEIGHT);
- I_SetPalette(W_CacheLumpName("E2PAL", PU_CACHE));
- V_DrawRawScreen(W_CacheLumpName("E2END", PU_CACHE));
+ I_SetPalette(W_CacheLumpName(DEH_String("E2PAL"), PU_CACHE));
+ V_DrawRawScreen(W_CacheLumpName(DEH_String("E2END"), PU_CACHE));
}
paused = false;
MenuActive = false;
@@ -328,7 +324,7 @@ void F_DrawUnderwater(void)
break;
case 2:
- V_DrawRawScreen(W_CacheLumpName("TITLE", PU_CACHE));
+ V_DrawRawScreen(W_CacheLumpName(DEH_String("TITLE"), PU_CACHE));
//D_StartTitle(); // go to intro/demo mode.
}
}
diff --git a/src/heretic/g_game.c b/src/heretic/g_game.c
index a256b63b..b37f95e0 100644
--- a/src/heretic/g_game.c
+++ b/src/heretic/g_game.c
@@ -28,6 +28,7 @@
#include <string.h>
#include "doomdef.h"
#include "doomkeys.h"
+#include "deh_str.h"
#include "i_timer.h"
#include "i_system.h"
#include "m_controls.h"
@@ -862,12 +863,16 @@ void G_Ticker(void)
{
if (netgame)
{
- strcpy(savedescription, "NET GAME");
+ strncpy(savedescription, DEH_String("NET GAME"),
+ sizeof(savedescription));
}
else
{
- strcpy(savedescription, "SAVE GAME");
+ strncpy(savedescription, DEH_String("SAVE GAME"),
+ sizeof(savedescription));
}
+
+ savedescription[sizeof(savedescription) - 1] = '\0';
}
savegameslot =
(players[i].cmd.
@@ -1320,7 +1325,9 @@ void G_DoLoadGame(void)
save_p = savebuffer + SAVESTRINGSIZE;
// Skip the description field
memset(vcheck, 0, sizeof(vcheck));
- sprintf(vcheck, "version %i", HERETIC_VERSION);
+
+ DEH_snprintf(vcheck, VERSIONSIZE, "version %i", HERETIC_VERSION);
+
if (strcmp((char *) save_p, vcheck) != 0)
{ // Bad version
return;
@@ -1449,11 +1456,11 @@ void G_InitNew(skill_t skill, int episode, int map)
// Set the sky map
if (episode > 5)
{
- skytexture = R_TextureNumForName("SKY1");
+ skytexture = R_TextureNumForName(DEH_String("SKY1"));
}
else
{
- skytexture = R_TextureNumForName(skyLumpNames[episode - 1]);
+ skytexture = R_TextureNumForName(DEH_String(skyLumpNames[episode - 1]));
}
//
@@ -1694,7 +1701,7 @@ void G_DoSaveGame(void)
SV_Open(name);
SV_Write(description, SAVESTRINGSIZE);
memset(verString, 0, sizeof(verString));
- sprintf(verString, "version %i", HERETIC_VERSION);
+ DEH_snprintf(verString, VERSIONSIZE, "version %i", HERETIC_VERSION);
SV_Write(verString, VERSIONSIZE);
SV_WriteByte(gameskill);
SV_WriteByte(gameepisode);
@@ -1714,7 +1721,7 @@ void G_DoSaveGame(void)
gameaction = ga_nothing;
savedescription[0] = 0;
- P_SetMessage(&players[consoleplayer], TXT_GAMESAVED, true);
+ P_SetMessage(&players[consoleplayer], DEH_String(TXT_GAMESAVED), true);
}
//==========================================================================
diff --git a/src/heretic/in_lude.c b/src/heretic/in_lude.c
index 33b75956..3c382814 100644
--- a/src/heretic/in_lude.c
+++ b/src/heretic/in_lude.c
@@ -30,6 +30,7 @@
*/
#include "doomdef.h"
+#include "deh_str.h"
#include "s_sound.h"
#include "i_system.h"
#include "i_video.h"
@@ -161,7 +162,7 @@ extern void AM_Stop(void);
void IN_Start(void)
{
- I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE));
+ I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE));
IN_LoadPics();
IN_InitStats();
intermission = true;
@@ -308,26 +309,26 @@ static void IN_LoadUnloadPics(void (*callback)(char *lumpname,
switch (gameepisode)
{
case 1:
- callback("MAPE1", 0, &patchINTERPIC);
+ callback(DEH_String("MAPE1"), 0, &patchINTERPIC);
break;
case 2:
- callback("MAPE2", 0, &patchINTERPIC);
+ callback(DEH_String("MAPE2"), 0, &patchINTERPIC);
break;
case 3:
- callback("MAPE3", 0, &patchINTERPIC);
+ callback(DEH_String("MAPE3"), 0, &patchINTERPIC);
break;
default:
break;
}
- callback("IN_X", 0, &patchBEENTHERE);
- callback("IN_YAH", 0, &patchGOINGTHERE);
- callback("FONTB13", 0, &FontBNegative);
+ callback(DEH_String("IN_X"), 0, &patchBEENTHERE);
+ callback(DEH_String("IN_YAH"), 0, &patchGOINGTHERE);
+ callback(DEH_String("FONTB13"), 0, &FontBNegative);
- callback("FONTB15", 0, &FontBSlash);
- callback("FONTB05", 0, &FontBPercent);
+ callback(DEH_String("FONTB15"), 0, &FontBSlash);
+ callback(DEH_String("FONTB05"), 0, &FontBPercent);
- FontBLumpBase = W_GetNumForName("FONTB16");
+ FontBLumpBase = W_GetNumForName(DEH_String("FONTB16"));
for (i = 0; i < 10; i++)
{
@@ -355,9 +356,9 @@ static void LoadLumpCallback(char *lumpname, int lumpnum, patch_t **ptr)
void IN_LoadPics(void)
{
- FontBLump = W_GetNumForName("FONTB_S") + 1;
- patchFaceOkayBase = W_GetNumForName("FACEA0");
- patchFaceDeadBase = W_GetNumForName("FACEB0");
+ FontBLump = W_GetNumForName(DEH_String("FONTB_S")) + 1;
+ patchFaceOkayBase = W_GetNumForName(DEH_String("FACEA0"));
+ patchFaceDeadBase = W_GetNumForName(DEH_String("FACEB0"));
IN_LoadUnloadPics(LoadLumpCallback);
}
@@ -580,7 +581,7 @@ void IN_DrawStatBack(void)
byte *src;
byte *dest;
- src = W_CacheLumpName("FLOOR16", PU_CACHE);
+ src = W_CacheLumpName(DEH_String("FLOOR16"), PU_CACHE);
dest = I_VideoBuffer;
for (y = 0; y < SCREENHEIGHT; y++)
@@ -612,8 +613,8 @@ void IN_DrawOldLevel(void)
x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] +
7) / 2;
IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3);
- x = 160 - MN_TextAWidth("FINISHED") / 2;
- MN_DrTextA("FINISHED", x, 25);
+ x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2;
+ MN_DrTextA(DEH_String("FINISHED"), x, 25);
if (prevmap == 9)
{
@@ -660,8 +661,8 @@ void IN_DrawYAH(void)
int i;
int x;
- x = 160 - MN_TextAWidth("NOW ENTERING:") / 2;
- MN_DrTextA("NOW ENTERING:", x, 10);
+ x = 160 - MN_TextAWidth(DEH_String("NOW ENTERING:")) / 2;
+ MN_DrTextA(DEH_String("NOW ENTERING:"), x, 10);
x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] +
7) / 2;
IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] + 7, x, 20);
@@ -698,15 +699,15 @@ void IN_DrawSingleStats(void)
int x;
static int sounds;
- IN_DrTextB("KILLS", 50, 65);
- IN_DrTextB("ITEMS", 50, 90);
- IN_DrTextB("SECRETS", 50, 115);
+ IN_DrTextB(DEH_String("KILLS"), 50, 65);
+ IN_DrTextB(DEH_String("ITEMS"), 50, 90);
+ IN_DrTextB(DEH_String("SECRETS"), 50, 115);
x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] +
7) / 2;
IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3);
- x = 160 - MN_TextAWidth("FINISHED") / 2;
- MN_DrTextA("FINISHED", x, 25);
+ x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2;
+ MN_DrTextA(DEH_String("FINISHED"), x, 25);
if (intertime < 30)
{
@@ -757,13 +758,13 @@ void IN_DrawSingleStats(void)
if (gamemode != retail || gameepisode <= 3)
{
- IN_DrTextB("TIME", 85, 160);
+ IN_DrTextB(DEH_String("TIME"), 85, 160);
IN_DrawTime(155, 160, hours, minutes, seconds);
}
else
{
- x = 160 - MN_TextAWidth("NOW ENTERING:") / 2;
- MN_DrTextA("NOW ENTERING:", x, 160);
+ x = 160 - MN_TextAWidth(DEH_String("NOW ENTERING:")) / 2;
+ MN_DrTextA(DEH_String("NOW ENTERING:"), x, 160);
x = 160 -
MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + gamemap - 1] +
7) / 2;
@@ -787,14 +788,14 @@ void IN_DrawCoopStats(void)
static int sounds;
- IN_DrTextB("KILLS", 95, 35);
- IN_DrTextB("BONUS", 155, 35);
- IN_DrTextB("SECRET", 232, 35);
+ IN_DrTextB(DEH_String("KILLS"), 95, 35);
+ IN_DrTextB(DEH_String("BONUS"), 155, 35);
+ IN_DrTextB(DEH_String("SECRET"), 232, 35);
x = 160 - MN_TextBWidth(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] +
7) / 2;
IN_DrTextB(LevelNames[(gameepisode - 1) * 9 + prevmap - 1] + 7, x, 3);
- x = 160 - MN_TextAWidth("FINISHED") / 2;
- MN_DrTextA("FINISHED", x, 25);
+ x = 160 - MN_TextAWidth(DEH_String("FINISHED")) / 2;
+ MN_DrTextA(DEH_String("FINISHED"), x, 25);
ypos = 50;
for (i = 0; i < MAXPLAYERS; i++)
@@ -845,11 +846,11 @@ void IN_DrawDMStats(void)
xpos = 90;
ypos = 55;
- IN_DrTextB("TOTAL", 265, 30);
- MN_DrTextA("VICTIMS", 140, 8);
+ IN_DrTextB(DEH_String("TOTAL"), 265, 30);
+ MN_DrTextA(DEH_String("VICTIMS"), 140, 8);
for (i = 0; i < 7; i++)
{
- MN_DrTextA(KillersText[i], 10, 80 + 9 * i);
+ MN_DrTextA(DEH_String(KillersText[i]), 10, 80 + 9 * i);
}
if (intertime < 20)
{
@@ -940,7 +941,7 @@ void IN_DrawTime(int x, int y, int h, int m, int s)
if (h)
{
IN_DrawNumber(h, x, y, 2);
- IN_DrTextB(":", x + 26, y);
+ IN_DrTextB(DEH_String(":"), x + 26, y);
}
x += 34;
if (m || h)
@@ -950,7 +951,7 @@ void IN_DrawTime(int x, int y, int h, int m, int s)
x += 34;
if (s)
{
- IN_DrTextB(":", x - 8, y);
+ IN_DrTextB(DEH_String(":"), x - 8, y);
IN_DrawNumber(s, x, y, 2);
}
}
diff --git a/src/heretic/info.c b/src/heretic/info.c
index e566222c..b6dd921f 100644
--- a/src/heretic/info.c
+++ b/src/heretic/info.c
@@ -22,7 +22,7 @@
//
//-----------------------------------------------------------------------------
#include "doomdef.h"
-// generated by multigen
+#include "p_action.h"
char *sprnames[] = {
"IMPX","ACLO","PTN1","SHLD","SHD2","BAGH","SPMP","INVS","PTN2","SOAR",
@@ -41,132 +41,6 @@ char *sprnames[] = {
NULL
};
-void A_FreeTargMobj();
-void A_RestoreSpecialThing1();
-void A_RestoreSpecialThing2();
-void A_HideThing();
-void A_UnHideThing();
-void A_RestoreArtifact();
-void A_Scream();
-void A_Explode();
-void A_PodPain();
-void A_RemovePod();
-void A_MakePod();
-void A_InitKeyGizmo();
-void A_VolcanoSet();
-void A_VolcanoBlast();
-void A_BeastPuff();
-void A_VolcBallImpact();
-void A_SpawnTeleGlitter();
-void A_SpawnTeleGlitter2();
-void A_AccTeleGlitter();
-void A_Light0();
-void A_WeaponReady();
-void A_Lower();
-void A_Raise();
-void A_StaffAttackPL1();
-void A_ReFire();
-void A_StaffAttackPL2();
-void A_BeakReady();
-void A_BeakRaise();
-void A_BeakAttackPL1();
-void A_BeakAttackPL2();
-void A_GauntletAttack();
-void A_FireBlasterPL1();
-void A_FireBlasterPL2();
-void A_SpawnRippers();
-void A_FireMacePL1();
-void A_FireMacePL2();
-void A_MacePL1Check();
-void A_MaceBallImpact();
-void A_MaceBallImpact2();
-void A_DeathBallImpact();
-void A_FireSkullRodPL1();
-void A_FireSkullRodPL2();
-void A_SkullRodPL2Seek();
-void A_AddPlayerRain();
-void A_HideInCeiling();
-void A_SkullRodStorm();
-void A_RainImpact();
-void A_FireGoldWandPL1();
-void A_FireGoldWandPL2();
-void A_FirePhoenixPL1();
-void A_InitPhoenixPL2();
-void A_FirePhoenixPL2();
-void A_ShutdownPhoenixPL2();
-void A_PhoenixPuff();
-void A_FlameEnd();
-void A_FloatPuff();
-void A_FireCrossbowPL1();
-void A_FireCrossbowPL2();
-void A_BoltSpark();
-void A_Pain();
-void A_NoBlocking();
-void A_AddPlayerCorpse();
-void A_SkullPop();
-void A_FlameSnd();
-void A_CheckBurnGone();
-void A_CheckSkullFloor();
-void A_CheckSkullDone();
-void A_Feathers();
-void A_ChicLook();
-void A_ChicChase();
-void A_ChicPain();
-void A_FaceTarget();
-void A_ChicAttack();
-void A_Look();
-void A_Chase();
-void A_MummyAttack();
-void A_MummyAttack2();
-void A_MummySoul();
-void A_ContMobjSound();
-void A_MummyFX1Seek();
-void A_BeastAttack();
-void A_SnakeAttack();
-void A_SnakeAttack2();
-void A_HeadAttack();
-void A_BossDeath();
-void A_HeadIceImpact();
-void A_HeadFireGrow();
-void A_WhirlwindSeek();
-void A_ClinkAttack();
-void A_WizAtk1();
-void A_WizAtk2();
-void A_WizAtk3();
-void A_GhostOff();
-void A_ImpMeAttack();
-void A_ImpMsAttack();
-void A_ImpMsAttack2();
-void A_ImpDeath();
-void A_ImpXDeath1();
-void A_ImpXDeath2();
-void A_ImpExplode();
-void A_KnightAttack();
-void A_DripBlood();
-void A_Sor1Chase();
-void A_Sor1Pain();
-void A_Srcr1Attack();
-void A_SorZap();
-void A_SorcererRise();
-void A_SorRise();
-void A_SorSightSnd();
-void A_Srcr2Decide();
-void A_Srcr2Attack();
-void A_Sor2DthInit();
-void A_SorDSph();
-void A_Sor2DthLoop();
-void A_SorDExp();
-void A_SorDBon();
-void A_BlueSpark();
-void A_GenWizard();
-void A_MinotaurAtk1();
-void A_MinotaurDecide();
-void A_MinotaurAtk2();
-void A_MinotaurAtk3();
-void A_MinotaurCharge();
-void A_MntrFloorFire();
-void A_ESound();
-
state_t states[NUMSTATES] = {
{SPR_IMPX, 0, -1, NULL, S_NULL, 0, 0}, // S_NULL
{SPR_ACLO, 4, 1050, A_FreeTargMobj, S_NULL, 0, 0}, // S_FREETARGMOBJ
@@ -663,6 +537,9 @@ state_t states[NUMSTATES] = {
{SPR_FX08, 32773, 4, NULL, S_PHOENIXFXI1_7, 0, 0}, // S_PHOENIXFXI1_6
{SPR_FX08, 32774, 4, NULL, S_PHOENIXFXI1_8, 0, 0}, // S_PHOENIXFXI1_7
{SPR_FX08, 32775, 4, NULL, S_NULL, 0, 0}, // S_PHOENIXFXI1_8
+ {SPR_FX08, 32776, 8, NULL, S_PHOENIXFXIX_1, 0, 0 }, // S_PHOENIXFXIX_1
+ {SPR_FX08, 32777, 8, A_RemovedPhoenixFunc, S_PHOENIXFXIX_2, 0, 0 }, // S_PHOENIXFXIX_2
+ {SPR_FX08, 32778, 8, NULL, S_NULL, 0, 0 }, // S_PHOENIXFXIX_3
{SPR_FX04, 1, 4, NULL, S_PHOENIXPUFF2, 0, 0}, // S_PHOENIXPUFF1
{SPR_FX04, 2, 4, NULL, S_PHOENIXPUFF3, 0, 0}, // S_PHOENIXPUFF2
{SPR_FX04, 3, 4, NULL, S_PHOENIXPUFF4, 0, 0}, // S_PHOENIXPUFF3
@@ -3727,6 +3604,37 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = {
MF2_THRUGHOST | MF2_NOTELEPORT // flags2
},
+ // The following thing is present in the mobjinfo table from Heretic 1.0,
+ // but not in Heretic 1.3 (ie. it was removed). It has been re-inserted
+ // here to support HHE patches.
+
+ { // MT_PHOENIXFX_REMOVED
+ -1, // doomednum
+ S_PHOENIXFXIX_1, // spawnstate
+ 1000, // spawnhealth
+ S_NULL, // seestate
+ sfx_None, // seesound
+ 8, // reactiontime
+ sfx_None, // attacksound
+ S_NULL, // painstate
+ 0, // painchance
+ sfx_None, // painsound
+ S_NULL, // meleestate
+ S_NULL, // missilestate
+ S_NULL, // crashstate
+ S_PHOENIXFXIX_3, // deathstate
+ S_NULL, // xdeathstate
+ sfx_None, // deathsound
+ 0, // speed
+ 2 * FRACUNIT, // radius
+ 4 * FRACUNIT, // height
+ 100, // mass
+ 0, // damage
+ sfx_None, // activesound
+ MF_NOBLOCKMAP | MF_MISSILE | MF_DROPOFF | MF_NOGRAVITY, // flags
+ MF2_NOTELEPORT // flags2
+ },
+
{ // MT_PHOENIXPUFF
-1, // doomednum
S_PHOENIXPUFF1, // spawnstate
diff --git a/src/heretic/info.h b/src/heretic/info.h
index f9581298..236826cb 100644
--- a/src/heretic/info.h
+++ b/src/heretic/info.h
@@ -21,7 +21,9 @@
// 02111-1307, USA.
//
//-----------------------------------------------------------------------------
-// generated by multigen
+
+#ifndef HERETIC_INFO_H
+#define HERETIC_INFO_H
typedef enum
{
@@ -653,6 +655,9 @@ typedef enum
S_PHOENIXFXI1_6,
S_PHOENIXFXI1_7,
S_PHOENIXFXI1_8,
+ S_PHOENIXFXIX_1, // [ States in Heretic 1.0 that were removed
+ S_PHOENIXFXIX_2,
+ S_PHOENIXFXIX_3, // ]
S_PHOENIXPUFF1,
S_PHOENIXPUFF2,
S_PHOENIXPUFF3,
@@ -773,8 +778,8 @@ typedef enum
S_PLAY_FDTH16,
S_PLAY_FDTH17,
S_PLAY_FDTH18,
- S_PLAY_FDTH19,
- S_PLAY_FDTH20,
+ S_PLAY_FDTH19, // < These two frames were not present in the Heretic
+ S_PLAY_FDTH20, // < 1.0 executable (fire death animation was extended)
S_BLOODYSKULL1,
S_BLOODYSKULL2,
S_BLOODYSKULL3,
@@ -1470,6 +1475,7 @@ typedef enum
MT_GOLDWANDPUFF2,
MT_WPHOENIXROD,
MT_PHOENIXFX1,
+ MT_PHOENIXFX_REMOVED, // In Heretic 1.0, but removed.
MT_PHOENIXPUFF,
MT_PHOENIXFX2,
MT_MISC15,
@@ -1575,3 +1581,6 @@ typedef struct
} mobjinfo_t;
extern mobjinfo_t mobjinfo[NUMMOBJTYPES];
+
+#endif /* #ifndef HERETIC_INFO_H */
+
diff --git a/src/heretic/mn_menu.c b/src/heretic/mn_menu.c
index 33024a96..955e0124 100644
--- a/src/heretic/mn_menu.c
+++ b/src/heretic/mn_menu.c
@@ -25,6 +25,8 @@
// MN_menu.c
#include <ctype.h>
+
+#include "deh_str.h"
#include "doomdef.h"
#include "doomkeys.h"
#include "i_system.h"
@@ -73,7 +75,7 @@ typedef struct
{
ItemType_t type;
char *text;
- boolean(*func) (int option);
+ boolean(*func) (int option);
int option;
MenuType_t menu;
} MenuItem_t;
@@ -305,7 +307,7 @@ void MN_Init(void)
InitFonts();
MenuActive = false;
messageson = true;
- SkullBaseLump = W_GetNumForName("M_SKL00");
+ SkullBaseLump = W_GetNumForName(DEH_String("M_SKL00"));
if (gamemode == retail)
{ // Add episodes 4 and 5 to the menu
@@ -322,8 +324,8 @@ void MN_Init(void)
static void InitFonts(void)
{
- FontABaseLump = W_GetNumForName("FONTA_S") + 1;
- FontBBaseLump = W_GetNumForName("FONTB_S") + 1;
+ FontABaseLump = W_GetNumForName(DEH_String("FONTA_S")) + 1;
+ FontBBaseLump = W_GetNumForName(DEH_String("FONTB_S")) + 1;
}
//---------------------------------------------------------------------------
@@ -476,26 +478,28 @@ void MN_Drawer(void)
int x;
int y;
MenuItem_t *item;
+ char *message;
char *selName;
if (MenuActive == false)
{
if (askforquit)
{
- MN_DrTextA(QuitEndMsg[typeofask - 1], 160 -
- MN_TextAWidth(QuitEndMsg[typeofask - 1]) / 2, 80);
+ message = DEH_String(QuitEndMsg[typeofask - 1]);
+
+ MN_DrTextA(message, 160 - MN_TextAWidth(message) / 2, 80);
if (typeofask == 3)
{
MN_DrTextA(SlotText[quicksave - 1], 160 -
MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
- MN_DrTextA("?", 160 +
+ MN_DrTextA(DEH_String("?"), 160 +
MN_TextAWidth(SlotText[quicksave - 1]) / 2, 90);
}
if (typeofask == 4)
{
MN_DrTextA(SlotText[quickload - 1], 160 -
MN_TextAWidth(SlotText[quickload - 1]) / 2, 90);
- MN_DrTextA("?", 160 +
+ MN_DrTextA(DEH_String("?"), 160 +
MN_TextAWidth(SlotText[quickload - 1]) / 2, 90);
}
UpdateState |= I_FULLSCRN;
@@ -525,13 +529,13 @@ void MN_Drawer(void)
{
if (item->type != ITT_EMPTY && item->text)
{
- MN_DrTextB(item->text, x, y);
+ MN_DrTextB(DEH_String(item->text), x, y);
}
y += ITEM_HEIGHT;
item++;
}
y = CurrentMenu->y + (CurrentItPos * ITEM_HEIGHT) + SELECTOR_YOFFSET;
- selName = MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2";
+ selName = DEH_String(MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2");
V_DrawPatch(x + SELECTOR_XOFFSET, y,
W_CacheLumpName(selName, PU_CACHE));
}
@@ -548,7 +552,7 @@ static void DrawMainMenu(void)
int frame;
frame = (MenuTime / 3) % 18;
- V_DrawPatch(88, 0, W_CacheLumpName("M_HTIC", PU_CACHE));
+ V_DrawPatch(88, 0, W_CacheLumpName(DEH_String("M_HTIC"), PU_CACHE));
V_DrawPatch(40, 10, W_CacheLumpNum(SkullBaseLump + (17 - frame),
PU_CACHE));
V_DrawPatch(232, 10, W_CacheLumpNum(SkullBaseLump + frame, PU_CACHE));
@@ -597,7 +601,11 @@ static void DrawFilesMenu(void)
static void DrawLoadMenu(void)
{
- MN_DrTextB("LOAD GAME", 160 - MN_TextBWidth("LOAD GAME") / 2, 10);
+ char *title;
+
+ title = DEH_String("LOAD GAME");
+
+ MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 10);
if (!slottextloaded)
{
MN_LoadSlotText();
@@ -613,7 +621,11 @@ static void DrawLoadMenu(void)
static void DrawSaveMenu(void)
{
- MN_DrTextB("SAVE GAME", 160 - MN_TextBWidth("SAVE GAME") / 2, 10);
+ char *title;
+
+ title = DEH_String("SAVE GAME");
+
+ MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 10);
if (!slottextloaded)
{
MN_LoadSlotText();
@@ -675,7 +687,7 @@ static void DrawFileSlots(Menu_t * menu)
y = menu->y;
for (i = 0; i < 6; i++)
{
- V_DrawPatch(x, y, W_CacheLumpName("M_FSLOT", PU_CACHE));
+ V_DrawPatch(x, y, W_CacheLumpName(DEH_String("M_FSLOT"), PU_CACHE));
if (SlotStatus[i])
{
MN_DrTextA(SlotText[i], x + 5, y + 5);
@@ -694,11 +706,11 @@ static void DrawOptionsMenu(void)
{
if (messageson)
{
- MN_DrTextB("ON", 196, 50);
+ MN_DrTextB(DEH_String("ON"), 196, 50);
}
else
{
- MN_DrTextB("OFF", 196, 50);
+ MN_DrTextB(DEH_String("OFF"), 196, 50);
}
DrawSlider(&OptionsMenu, 3, 10, mouseSensitivity);
}
@@ -796,11 +808,11 @@ static boolean SCMessages(int option)
messageson ^= 1;
if (messageson)
{
- P_SetMessage(&players[consoleplayer], "MESSAGES ON", true);
+ P_SetMessage(&players[consoleplayer], DEH_String("MESSAGES ON"), true);
}
else
{
- P_SetMessage(&players[consoleplayer], "MESSAGES OFF", true);
+ P_SetMessage(&players[consoleplayer], DEH_String("MESSAGES OFF"), true);
}
S_StartSound(NULL, sfx_chat);
return true;
@@ -1460,7 +1472,7 @@ boolean MN_Responder(event_t * event)
if (CurrentMenu->items[i].text)
{
if (toupper(charTyped)
- == toupper(CurrentMenu->items[i].text[0]))
+ == toupper(DEH_String(CurrentMenu->items[i].text)[0]))
{
CurrentItPos = i;
return (true);
@@ -1628,13 +1640,13 @@ static void DrawSlider(Menu_t * menu, int item, int width, int slot)
x = menu->x + 24;
y = menu->y + 2 + (item * ITEM_HEIGHT);
- V_DrawPatch(x - 32, y, W_CacheLumpName("M_SLDLT", PU_CACHE));
+ V_DrawPatch(x - 32, y, W_CacheLumpName(DEH_String("M_SLDLT"), PU_CACHE));
for (x2 = x, count = width; count--; x2 += 8)
{
- V_DrawPatch(x2, y, W_CacheLumpName(count & 1 ? "M_SLDMD1"
- : "M_SLDMD2", PU_CACHE));
+ V_DrawPatch(x2, y, W_CacheLumpName(DEH_String(count & 1 ? "M_SLDMD1"
+ : "M_SLDMD2"), PU_CACHE));
}
- V_DrawPatch(x2, y, W_CacheLumpName("M_SLDRT", PU_CACHE));
+ V_DrawPatch(x2, y, W_CacheLumpName(DEH_String("M_SLDRT"), PU_CACHE));
V_DrawPatch(x + 4 + slot * 8, y + 7,
- W_CacheLumpName("M_SLDKB", PU_CACHE));
+ W_CacheLumpName(DEH_String("M_SLDKB"), PU_CACHE));
}
diff --git a/src/heretic/p_action.h b/src/heretic/p_action.h
new file mode 100644
index 00000000..8d8e383c
--- /dev/null
+++ b/src/heretic/p_action.h
@@ -0,0 +1,160 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 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.
+//
+//-----------------------------------------------------------------------------
+//
+// External definitions for action pointer functions.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef HERETIC_P_ACTION_H
+#define HERETIC_P_ACTION_H
+
+void A_FreeTargMobj();
+void A_RestoreSpecialThing1();
+void A_RestoreSpecialThing2();
+void A_HideThing();
+void A_UnHideThing();
+void A_RestoreArtifact();
+void A_Scream();
+void A_Explode();
+void A_PodPain();
+void A_RemovePod();
+void A_MakePod();
+void A_InitKeyGizmo();
+void A_VolcanoSet();
+void A_VolcanoBlast();
+void A_BeastPuff();
+void A_VolcBallImpact();
+void A_SpawnTeleGlitter();
+void A_SpawnTeleGlitter2();
+void A_AccTeleGlitter();
+void A_Light0();
+void A_WeaponReady();
+void A_Lower();
+void A_Raise();
+void A_StaffAttackPL1();
+void A_ReFire();
+void A_StaffAttackPL2();
+void A_BeakReady();
+void A_BeakRaise();
+void A_BeakAttackPL1();
+void A_BeakAttackPL2();
+void A_GauntletAttack();
+void A_FireBlasterPL1();
+void A_FireBlasterPL2();
+void A_SpawnRippers();
+void A_FireMacePL1();
+void A_FireMacePL2();
+void A_MacePL1Check();
+void A_MaceBallImpact();
+void A_MaceBallImpact2();
+void A_DeathBallImpact();
+void A_FireSkullRodPL1();
+void A_FireSkullRodPL2();
+void A_SkullRodPL2Seek();
+void A_AddPlayerRain();
+void A_HideInCeiling();
+void A_SkullRodStorm();
+void A_RainImpact();
+void A_FireGoldWandPL1();
+void A_FireGoldWandPL2();
+void A_FirePhoenixPL1();
+void A_InitPhoenixPL2();
+void A_FirePhoenixPL2();
+void A_ShutdownPhoenixPL2();
+void A_PhoenixPuff();
+void A_RemovedPhoenixFunc();
+void A_FlameEnd();
+void A_FloatPuff();
+void A_FireCrossbowPL1();
+void A_FireCrossbowPL2();
+void A_BoltSpark();
+void A_Pain();
+void A_NoBlocking();
+void A_AddPlayerCorpse();
+void A_SkullPop();
+void A_FlameSnd();
+void A_CheckBurnGone();
+void A_CheckSkullFloor();
+void A_CheckSkullDone();
+void A_Feathers();
+void A_ChicLook();
+void A_ChicChase();
+void A_ChicPain();
+void A_FaceTarget();
+void A_ChicAttack();
+void A_Look();
+void A_Chase();
+void A_MummyAttack();
+void A_MummyAttack2();
+void A_MummySoul();
+void A_ContMobjSound();
+void A_MummyFX1Seek();
+void A_BeastAttack();
+void A_SnakeAttack();
+void A_SnakeAttack2();
+void A_HeadAttack();
+void A_BossDeath();
+void A_HeadIceImpact();
+void A_HeadFireGrow();
+void A_WhirlwindSeek();
+void A_ClinkAttack();
+void A_WizAtk1();
+void A_WizAtk2();
+void A_WizAtk3();
+void A_GhostOff();
+void A_ImpMeAttack();
+void A_ImpMsAttack();
+void A_ImpMsAttack2();
+void A_ImpDeath();
+void A_ImpXDeath1();
+void A_ImpXDeath2();
+void A_ImpExplode();
+void A_KnightAttack();
+void A_DripBlood();
+void A_Sor1Chase();
+void A_Sor1Pain();
+void A_Srcr1Attack();
+void A_SorZap();
+void A_SorcererRise();
+void A_SorRise();
+void A_SorSightSnd();
+void A_Srcr2Decide();
+void A_Srcr2Attack();
+void A_Sor2DthInit();
+void A_SorDSph();
+void A_Sor2DthLoop();
+void A_SorDExp();
+void A_SorDBon();
+void A_BlueSpark();
+void A_GenWizard();
+void A_MinotaurAtk1();
+void A_MinotaurDecide();
+void A_MinotaurAtk2();
+void A_MinotaurAtk3();
+void A_MinotaurCharge();
+void A_MntrFloorFire();
+void A_ESound();
+
+#endif /* #ifndef HERETIC_P_ACTION_H */
+
diff --git a/src/heretic/p_doors.c b/src/heretic/p_doors.c
index e0e82fbe..56e37119 100644
--- a/src/heretic/p_doors.c
+++ b/src/heretic/p_doors.c
@@ -25,6 +25,7 @@
// P_doors.c
#include "doomdef.h"
+#include "deh_str.h"
#include "p_local.h"
#include "s_sound.h"
#include "v_video.h"
@@ -232,7 +233,7 @@ void EV_VerticalDoor(line_t * line, mobj_t * thing)
}
if (!player->keys[key_blue])
{
- P_SetMessage(player, TXT_NEEDBLUEKEY, false);
+ P_SetMessage(player, DEH_String(TXT_NEEDBLUEKEY), false);
S_StartSound(NULL, sfx_plroof);
return;
}
@@ -245,7 +246,7 @@ void EV_VerticalDoor(line_t * line, mobj_t * thing)
}
if (!player->keys[key_yellow])
{
- P_SetMessage(player, TXT_NEEDYELLOWKEY, false);
+ P_SetMessage(player, DEH_String(TXT_NEEDYELLOWKEY), false);
S_StartSound(NULL, sfx_plroof);
return;
}
@@ -258,7 +259,7 @@ void EV_VerticalDoor(line_t * line, mobj_t * thing)
}
if (!player->keys[key_green])
{
- P_SetMessage(player, TXT_NEEDGREENKEY, false);
+ P_SetMessage(player, DEH_String(TXT_NEEDGREENKEY), false);
S_StartSound(NULL, sfx_plroof);
return;
}
diff --git a/src/heretic/p_inter.c b/src/heretic/p_inter.c
index fba6d215..afdb37f2 100644
--- a/src/heretic/p_inter.c
+++ b/src/heretic/p_inter.c
@@ -25,6 +25,7 @@
// P_inter.c
#include "doomdef.h"
+#include "deh_str.h"
#include "i_system.h"
#include "i_timer.h"
#include "m_random.h"
@@ -54,7 +55,7 @@ int maxammo[NUMAMMO] = {
150 // mace
};
-static int GetWeaponAmmo[NUMWEAPONS] = {
+int GetWeaponAmmo[NUMWEAPONS] = {
0, // staff
25, // gold wand
10, // crossbow
@@ -580,21 +581,21 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
{
return;
}
- P_SetMessage(player, TXT_ITEMHEALTH, false);
+ P_SetMessage(player, DEH_String(TXT_ITEMHEALTH), false);
break;
case SPR_SHLD: // Item_Shield1
if (!P_GiveArmor(player, 1))
{
return;
}
- P_SetMessage(player, TXT_ITEMSHIELD1, false);
+ P_SetMessage(player, DEH_String(TXT_ITEMSHIELD1), false);
break;
case SPR_SHD2: // Item_Shield2
if (!P_GiveArmor(player, 2))
{
return;
}
- P_SetMessage(player, TXT_ITEMSHIELD2, false);
+ P_SetMessage(player, DEH_String(TXT_ITEMSHIELD2), false);
break;
case SPR_BAGH: // Item_BagOfHolding
if (!player->backpack)
@@ -610,21 +611,21 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
P_GiveAmmo(player, am_crossbow, AMMO_CBOW_WIMPY);
P_GiveAmmo(player, am_skullrod, AMMO_SKRD_WIMPY);
P_GiveAmmo(player, am_phoenixrod, AMMO_PHRD_WIMPY);
- P_SetMessage(player, TXT_ITEMBAGOFHOLDING, false);
+ P_SetMessage(player, DEH_String(TXT_ITEMBAGOFHOLDING), false);
break;
case SPR_SPMP: // Item_SuperMap
if (!P_GivePower(player, pw_allmap))
{
return;
}
- P_SetMessage(player, TXT_ITEMSUPERMAP, false);
+ P_SetMessage(player, DEH_String(TXT_ITEMSUPERMAP), false);
break;
// Keys
case SPR_BKYY: // Key_Blue
if (!player->keys[key_blue])
{
- P_SetMessage(player, TXT_GOTBLUEKEY, false);
+ P_SetMessage(player, DEH_String(TXT_GOTBLUEKEY), false);
}
P_GiveKey(player, key_blue);
sound = sfx_keyup;
@@ -636,7 +637,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
case SPR_CKYY: // Key_Yellow
if (!player->keys[key_yellow])
{
- P_SetMessage(player, TXT_GOTYELLOWKEY, false);
+ P_SetMessage(player, DEH_String(TXT_GOTYELLOWKEY), false);
}
sound = sfx_keyup;
P_GiveKey(player, key_yellow);
@@ -648,7 +649,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
case SPR_AKYY: // Key_Green
if (!player->keys[key_green])
{
- P_SetMessage(player, TXT_GOTGREENKEY, false);
+ P_SetMessage(player, DEH_String(TXT_GOTGREENKEY), false);
}
sound = sfx_keyup;
P_GiveKey(player, key_green);
@@ -662,70 +663,70 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
case SPR_PTN2: // Arti_HealingPotion
if (P_GiveArtifact(player, arti_health, special))
{
- P_SetMessage(player, TXT_ARTIHEALTH, false);
+ P_SetMessage(player, DEH_String(TXT_ARTIHEALTH), false);
P_SetDormantArtifact(special);
}
return;
case SPR_SOAR: // Arti_Fly
if (P_GiveArtifact(player, arti_fly, special))
{
- P_SetMessage(player, TXT_ARTIFLY, false);
+ P_SetMessage(player, DEH_String(TXT_ARTIFLY), false);
P_SetDormantArtifact(special);
}
return;
case SPR_INVU: // Arti_Invulnerability
if (P_GiveArtifact(player, arti_invulnerability, special))
{
- P_SetMessage(player, TXT_ARTIINVULNERABILITY, false);
+ P_SetMessage(player, DEH_String(TXT_ARTIINVULNERABILITY), false);
P_SetDormantArtifact(special);
}
return;
case SPR_PWBK: // Arti_TomeOfPower
if (P_GiveArtifact(player, arti_tomeofpower, special))
{
- P_SetMessage(player, TXT_ARTITOMEOFPOWER, false);
+ P_SetMessage(player, DEH_String(TXT_ARTITOMEOFPOWER), false);
P_SetDormantArtifact(special);
}
return;
case SPR_INVS: // Arti_Invisibility
if (P_GiveArtifact(player, arti_invisibility, special))
{
- P_SetMessage(player, TXT_ARTIINVISIBILITY, false);
+ P_SetMessage(player, DEH_String(TXT_ARTIINVISIBILITY), false);
P_SetDormantArtifact(special);
}
return;
case SPR_EGGC: // Arti_Egg
if (P_GiveArtifact(player, arti_egg, special))
{
- P_SetMessage(player, TXT_ARTIEGG, false);
+ P_SetMessage(player, DEH_String(TXT_ARTIEGG), false);
P_SetDormantArtifact(special);
}
return;
case SPR_SPHL: // Arti_SuperHealth
if (P_GiveArtifact(player, arti_superhealth, special))
{
- P_SetMessage(player, TXT_ARTISUPERHEALTH, false);
+ P_SetMessage(player, DEH_String(TXT_ARTISUPERHEALTH), false);
P_SetDormantArtifact(special);
}
return;
case SPR_TRCH: // Arti_Torch
if (P_GiveArtifact(player, arti_torch, special))
{
- P_SetMessage(player, TXT_ARTITORCH, false);
+ P_SetMessage(player, DEH_String(TXT_ARTITORCH), false);
P_SetDormantArtifact(special);
}
return;
case SPR_FBMB: // Arti_FireBomb
if (P_GiveArtifact(player, arti_firebomb, special))
{
- P_SetMessage(player, TXT_ARTIFIREBOMB, false);
+ P_SetMessage(player, DEH_String(TXT_ARTIFIREBOMB), false);
P_SetDormantArtifact(special);
}
return;
case SPR_ATLP: // Arti_Teleport
if (P_GiveArtifact(player, arti_teleport, special))
{
- P_SetMessage(player, TXT_ARTITELEPORT, false);
+ P_SetMessage(player, DEH_String(TXT_ARTITELEPORT), false);
P_SetDormantArtifact(special);
}
return;
@@ -736,84 +737,84 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
{
return;
}
- P_SetMessage(player, TXT_AMMOGOLDWAND1, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOGOLDWAND1), false);
break;
case SPR_AMG2: // Ammo_GoldWandHefty
if (!P_GiveAmmo(player, am_goldwand, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOGOLDWAND2, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOGOLDWAND2), false);
break;
case SPR_AMM1: // Ammo_MaceWimpy
if (!P_GiveAmmo(player, am_mace, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOMACE1, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOMACE1), false);
break;
case SPR_AMM2: // Ammo_MaceHefty
if (!P_GiveAmmo(player, am_mace, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOMACE2, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOMACE2), false);
break;
case SPR_AMC1: // Ammo_CrossbowWimpy
if (!P_GiveAmmo(player, am_crossbow, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOCROSSBOW1, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOCROSSBOW1), false);
break;
case SPR_AMC2: // Ammo_CrossbowHefty
if (!P_GiveAmmo(player, am_crossbow, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOCROSSBOW2, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOCROSSBOW2), false);
break;
case SPR_AMB1: // Ammo_BlasterWimpy
if (!P_GiveAmmo(player, am_blaster, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOBLASTER1, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOBLASTER1), false);
break;
case SPR_AMB2: // Ammo_BlasterHefty
if (!P_GiveAmmo(player, am_blaster, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOBLASTER2, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOBLASTER2), false);
break;
case SPR_AMS1: // Ammo_SkullRodWimpy
if (!P_GiveAmmo(player, am_skullrod, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOSKULLROD1, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOSKULLROD1), false);
break;
case SPR_AMS2: // Ammo_SkullRodHefty
if (!P_GiveAmmo(player, am_skullrod, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOSKULLROD2, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOSKULLROD2), false);
break;
case SPR_AMP1: // Ammo_PhoenixRodWimpy
if (!P_GiveAmmo(player, am_phoenixrod, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOPHOENIXROD1, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOPHOENIXROD1), false);
break;
case SPR_AMP2: // Ammo_PhoenixRodHefty
if (!P_GiveAmmo(player, am_phoenixrod, special->health))
{
return;
}
- P_SetMessage(player, TXT_AMMOPHOENIXROD2, false);
+ P_SetMessage(player, DEH_String(TXT_AMMOPHOENIXROD2), false);
break;
// Weapons
@@ -822,7 +823,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
{
return;
}
- P_SetMessage(player, TXT_WPNMACE, false);
+ P_SetMessage(player, DEH_String(TXT_WPNMACE), false);
sound = sfx_wpnup;
break;
case SPR_WBOW: // Weapon_Crossbow
@@ -830,7 +831,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
{
return;
}
- P_SetMessage(player, TXT_WPNCROSSBOW, false);
+ P_SetMessage(player, DEH_String(TXT_WPNCROSSBOW), false);
sound = sfx_wpnup;
break;
case SPR_WBLS: // Weapon_Blaster
@@ -838,7 +839,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
{
return;
}
- P_SetMessage(player, TXT_WPNBLASTER, false);
+ P_SetMessage(player, DEH_String(TXT_WPNBLASTER), false);
sound = sfx_wpnup;
break;
case SPR_WSKL: // Weapon_SkullRod
@@ -846,7 +847,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
{
return;
}
- P_SetMessage(player, TXT_WPNSKULLROD, false);
+ P_SetMessage(player, DEH_String(TXT_WPNSKULLROD), false);
sound = sfx_wpnup;
break;
case SPR_WPHX: // Weapon_PhoenixRod
@@ -854,7 +855,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
{
return;
}
- P_SetMessage(player, TXT_WPNPHOENIXROD, false);
+ P_SetMessage(player, DEH_String(TXT_WPNPHOENIXROD), false);
sound = sfx_wpnup;
break;
case SPR_WGNT: // Weapon_Gauntlets
@@ -862,7 +863,7 @@ void P_TouchSpecialThing(mobj_t * special, mobj_t * toucher)
{
return;
}
- P_SetMessage(player, TXT_WPNGAUNTLETS, false);
+ P_SetMessage(player, DEH_String(TXT_WPNGAUNTLETS), false);
sound = sfx_wpnup;
break;
default:
diff --git a/src/heretic/p_pspr.c b/src/heretic/p_pspr.c
index 7f9660ac..bd47c9a1 100644
--- a/src/heretic/p_pspr.c
+++ b/src/heretic/p_pspr.c
@@ -1650,6 +1650,17 @@ void A_PhoenixPuff(mobj_t * actor)
puff->momz = 0;
}
+//
+// This function was present in the Heretic 1.0 executable for the
+// removed "secondary phoenix flash" object (MT_PHOENIXFX_REMOVED).
+// The purpose of this object is unknown, as is this function.
+//
+
+void A_RemovedPhoenixFunc(mobj_t *actor)
+{
+ I_Error("Action function invoked for removed Phoenix action!");
+}
+
//----------------------------------------------------------------------------
//
// PROC A_InitPhoenixPL2
diff --git a/src/heretic/p_spec.c b/src/heretic/p_spec.c
index 6227237b..49c067fa 100644
--- a/src/heretic/p_spec.c
+++ b/src/heretic/p_spec.c
@@ -25,6 +25,7 @@
// P_Spec.c
#include "doomdef.h"
+#include "deh_str.h"
#include "i_system.h"
#include "i_timer.h"
#include "m_random.h"
@@ -204,18 +205,12 @@ struct
int type;
} TerrainTypeDefs[] =
{
- {
- "FLTWAWA1", FLOOR_WATER},
- {
- "FLTFLWW1", FLOOR_WATER},
- {
- "FLTLAVA1", FLOOR_LAVA},
- {
- "FLATHUH1", FLOOR_LAVA},
- {
- "FLTSLUD1", FLOOR_SLUDGE},
- {
- "END", -1}
+ { "FLTWAWA1", FLOOR_WATER },
+ { "FLTFLWW1", FLOOR_WATER },
+ { "FLTLAVA1", FLOOR_LAVA },
+ { "FLATHUH1", FLOOR_LAVA },
+ { "FLTSLUD1", FLOOR_SLUDGE },
+ { "END", -1 }
};
mobj_t LavaInflictor;
@@ -266,35 +261,40 @@ void P_InitTerrainTypes(void)
void P_InitPicAnims(void)
{
+ char *startname;
+ char *endname;
int i;
lastanim = anims;
for (i = 0; animdefs[i].istexture != -1; i++)
{
+ startname = DEH_String(animdefs[i].startname);
+ endname = DEH_String(animdefs[i].endname);
+
if (animdefs[i].istexture)
{ // Texture animation
- if (R_CheckTextureNumForName(animdefs[i].startname) == -1)
+ if (R_CheckTextureNumForName(startname) == -1)
{ // Texture doesn't exist
continue;
}
- lastanim->picnum = R_TextureNumForName(animdefs[i].endname);
- lastanim->basepic = R_TextureNumForName(animdefs[i].startname);
+ lastanim->picnum = R_TextureNumForName(endname);
+ lastanim->basepic = R_TextureNumForName(startname);
}
else
{ // Flat animation
- if (W_CheckNumForName(animdefs[i].startname) == -1)
+ if (W_CheckNumForName(startname) == -1)
{ // Flat doesn't exist
continue;
}
- lastanim->picnum = R_FlatNumForName(animdefs[i].endname);
- lastanim->basepic = R_FlatNumForName(animdefs[i].startname);
+ 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",
- animdefs[i].startname, animdefs[i].endname);
+ startname, endname);
}
lastanim->speed = animdefs[i].speed;
lastanim++;
@@ -1132,7 +1132,7 @@ void P_SpawnSpecials(void)
int episode;
episode = 1;
- if (W_CheckNumForName("texture2") >= 0)
+ if (W_CheckNumForName(DEH_String("texture2")) >= 0)
episode = 2;
//
diff --git a/src/heretic/p_switch.c b/src/heretic/p_switch.c
index cef6a74b..2ec758b6 100644
--- a/src/heretic/p_switch.c
+++ b/src/heretic/p_switch.c
@@ -23,6 +23,7 @@
//-----------------------------------------------------------------------------
#include "doomdef.h"
+#include "deh_str.h"
#include "i_system.h"
#include "p_local.h"
#include "s_sound.h"
@@ -129,9 +130,9 @@ void P_InitSwitchList(void)
if (alphSwitchList[i].episode <= episode)
{
switchlist[index++] =
- R_TextureNumForName(alphSwitchList[i].name1);
+ R_TextureNumForName(DEH_String(alphSwitchList[i].name1));
switchlist[index++] =
- R_TextureNumForName(alphSwitchList[i].name2);
+ R_TextureNumForName(DEH_String(alphSwitchList[i].name2));
}
}
}
diff --git a/src/heretic/p_user.c b/src/heretic/p_user.c
index 63368bab..16dbed49 100644
--- a/src/heretic/p_user.c
+++ b/src/heretic/p_user.c
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include "doomdef.h"
+#include "deh_str.h"
#include "m_random.h"
#include "p_local.h"
#include "s_sound.h"
@@ -394,7 +395,7 @@ void P_DeathThink(player_t * player)
{
if (player == &players[consoleplayer])
{
- I_SetPalette((byte *) W_CacheLumpName("PLAYPAL", PU_CACHE));
+ I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE));
inv_ptr = 0;
curpos = 0;
newtorch = 0;
diff --git a/src/heretic/r_data.c b/src/heretic/r_data.c
index ee005248..5bb79aa4 100644
--- a/src/heretic/r_data.c
+++ b/src/heretic/r_data.c
@@ -25,6 +25,8 @@
// R_data.c
#include "doomdef.h"
+#include "deh_str.h"
+
#include "i_swap.h"
#include "i_system.h"
#include "r_local.h"
@@ -316,12 +318,17 @@ void R_InitTextures(void)
int offset, maxoff, maxoff2;
int numtextures1, numtextures2;
int *directory;
+ char *texture1, *texture2, *pnames;
+
+ texture1 = DEH_String("TEXTURE1");
+ texture2 = DEH_String("TEXTURE2");
+ pnames = DEH_String("PNAMES");
//
// load the patch names from pnames.lmp
//
name[8] = 0;
- names = W_CacheLumpName("PNAMES", PU_STATIC);
+ names = W_CacheLumpName(pnames, PU_STATIC);
nummappatches = LONG(*((int *) names));
name_p = names + 4;
patchlookup = Z_Malloc(nummappatches * sizeof(*patchlookup), PU_STATIC, NULL);
@@ -330,21 +337,21 @@ void R_InitTextures(void)
strncpy(name, name_p + i * 8, 8);
patchlookup[i] = W_CheckNumForName(name);
}
- W_ReleaseLumpName("PNAMES");
+ W_ReleaseLumpName(pnames);
//
// load the map texture definitions from textures.lmp
//
- maptex = maptex1 = W_CacheLumpName("TEXTURE1", PU_STATIC);
+ maptex = maptex1 = W_CacheLumpName(texture1, PU_STATIC);
numtextures1 = LONG(*maptex);
- maxoff = W_LumpLength(W_GetNumForName("TEXTURE1"));
+ maxoff = W_LumpLength(W_GetNumForName(texture1));
directory = maptex + 1;
- if (W_CheckNumForName("TEXTURE2") != -1)
+ if (W_CheckNumForName(texture2) != -1)
{
- maptex2 = W_CacheLumpName("TEXTURE2", PU_STATIC);
+ maptex2 = W_CacheLumpName(texture2, PU_STATIC);
numtextures2 = LONG(*maptex2);
- maxoff2 = W_LumpLength(W_GetNumForName("TEXTURE2"));
+ maxoff2 = W_LumpLength(W_GetNumForName(texture2));
}
else
{
@@ -358,8 +365,11 @@ void R_InitTextures(void)
// Init the startup thermometer at this point...
//
{
+ int start, end;
int spramount;
- spramount = W_GetNumForName("S_END") - W_GetNumForName("S_START") + 1;
+ start = W_GetNumForName(DEH_String("S_START"));
+ end = W_GetNumForName(DEH_String("S_END"));
+ spramount = end - start + 1;
InitThermo(spramount + numtextures + 6);
}
@@ -427,10 +437,10 @@ void R_InitTextures(void)
Z_Free(patchlookup);
- W_ReleaseLumpName("TEXTURE1");
+ W_ReleaseLumpName(texture1);
if (maptex2)
{
- W_ReleaseLumpName("TEXTURE2");
+ W_ReleaseLumpName(texture2);
}
//
@@ -463,8 +473,8 @@ void R_InitFlats(void)
{
int i;
- firstflat = W_GetNumForName("F_START") + 1;
- lastflat = W_GetNumForName("F_END") - 1;
+ firstflat = W_GetNumForName(DEH_String("F_START")) + 1;
+ lastflat = W_GetNumForName(DEH_String("F_END")) - 1;
numflats = lastflat - firstflat + 1;
// translation table for global animation
@@ -489,8 +499,8 @@ void R_InitSpriteLumps(void)
int i;
patch_t *patch;
- firstspritelump = W_GetNumForName("S_START") + 1;
- lastspritelump = W_GetNumForName("S_END") - 1;
+ 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(fixed_t), PU_STATIC, 0);
spriteoffset = Z_Malloc(numspritelumps * sizeof(fixed_t), PU_STATIC, 0);
@@ -527,7 +537,7 @@ void R_InitColormaps(void)
// load in the light tables
// 256 byte align tables
//
- lump = W_GetNumForName("COLORMAP");
+ lump = W_GetNumForName(DEH_String("COLORMAP"));
length = W_LumpLength(lump);
colormaps = Z_Malloc(length, PU_STATIC, 0);
W_ReadLump(lump, colormaps);
diff --git a/src/heretic/r_draw.c b/src/heretic/r_draw.c
index 5a20b50a..88653df1 100644
--- a/src/heretic/r_draw.c
+++ b/src/heretic/r_draw.c
@@ -24,6 +24,7 @@
// R_draw.c
#include "doomdef.h"
+#include "deh_str.h"
#include "r_local.h"
#include "i_video.h"
#include "v_video.h"
@@ -386,11 +387,11 @@ void R_DrawViewBorder(void)
if (gamemode == shareware)
{
- src = W_CacheLumpName("FLOOR04", PU_CACHE);
+ src = W_CacheLumpName(DEH_String("FLOOR04"), PU_CACHE);
}
else
{
- src = W_CacheLumpName("FLAT513", PU_CACHE);
+ src = W_CacheLumpName(DEH_String("FLAT513"), PU_CACHE);
}
dest = I_VideoBuffer;
@@ -409,24 +410,26 @@ void R_DrawViewBorder(void)
}
for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
{
- V_DrawPatch(x, viewwindowy - 4, W_CacheLumpName("bordt", PU_CACHE));
- V_DrawPatch(x, viewwindowy + viewheight, W_CacheLumpName("bordb",
- PU_CACHE));
+ V_DrawPatch(x, viewwindowy - 4,
+ W_CacheLumpName(DEH_String("bordt"), PU_CACHE));
+ V_DrawPatch(x, viewwindowy + viewheight,
+ W_CacheLumpName(DEH_String("bordb"), PU_CACHE));
}
for (y = viewwindowy; y < viewwindowy + viewheight; y += 16)
{
- V_DrawPatch(viewwindowx - 4, y, W_CacheLumpName("bordl", PU_CACHE));
- V_DrawPatch(viewwindowx + viewwidth, y, W_CacheLumpName("bordr",
- PU_CACHE));
+ V_DrawPatch(viewwindowx - 4, y,
+ W_CacheLumpName(DEH_String("bordl"), PU_CACHE));
+ V_DrawPatch(viewwindowx + viewwidth, y,
+ W_CacheLumpName(DEH_String("bordr"), PU_CACHE));
}
- V_DrawPatch(viewwindowx - 4, viewwindowy - 4, W_CacheLumpName("bordtl",
- PU_CACHE));
+ V_DrawPatch(viewwindowx - 4, viewwindowy - 4,
+ W_CacheLumpName(DEH_String("bordtl"), PU_CACHE));
V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4,
- W_CacheLumpName("bordtr", PU_CACHE));
+ W_CacheLumpName(DEH_String("bordtr"), PU_CACHE));
V_DrawPatch(viewwindowx + viewwidth, viewwindowy + viewheight,
- W_CacheLumpName("bordbr", PU_CACHE));
+ W_CacheLumpName(DEH_String("bordbr"), PU_CACHE));
V_DrawPatch(viewwindowx - 4, viewwindowy + viewheight,
- W_CacheLumpName("bordbl", PU_CACHE));
+ W_CacheLumpName(DEH_String("bordbl"), PU_CACHE));
}
/*
@@ -450,11 +453,11 @@ void R_DrawTopBorder(void)
if (gamemode == shareware)
{
- src = W_CacheLumpName("FLOOR04", PU_CACHE);
+ src = W_CacheLumpName(DEH_String("FLOOR04"), PU_CACHE);
}
else
{
- src = W_CacheLumpName("FLAT513", PU_CACHE);
+ src = W_CacheLumpName(DEH_String("FLAT513"), PU_CACHE);
}
dest = I_VideoBuffer;
@@ -476,20 +479,20 @@ void R_DrawTopBorder(void)
for (x = viewwindowx; x < viewwindowx + viewwidth; x += 16)
{
V_DrawPatch(x, viewwindowy - 4,
- W_CacheLumpName("bordt", PU_CACHE));
+ W_CacheLumpName(DEH_String("bordt"), PU_CACHE));
}
- V_DrawPatch(viewwindowx - 4, viewwindowy, W_CacheLumpName("bordl",
- PU_CACHE));
+ V_DrawPatch(viewwindowx - 4, viewwindowy,
+ W_CacheLumpName(DEH_String("bordl"), PU_CACHE));
V_DrawPatch(viewwindowx + viewwidth, viewwindowy,
- W_CacheLumpName("bordr", PU_CACHE));
+ W_CacheLumpName(DEH_String("bordr"), PU_CACHE));
V_DrawPatch(viewwindowx - 4, viewwindowy + 16,
- W_CacheLumpName("bordl", PU_CACHE));
+ W_CacheLumpName(DEH_String("bordl"), PU_CACHE));
V_DrawPatch(viewwindowx + viewwidth, viewwindowy + 16,
- W_CacheLumpName("bordr", PU_CACHE));
+ W_CacheLumpName(DEH_String("bordr"), PU_CACHE));
V_DrawPatch(viewwindowx - 4, viewwindowy - 4,
- W_CacheLumpName("bordtl", PU_CACHE));
+ W_CacheLumpName(DEH_String("bordtl"), PU_CACHE));
V_DrawPatch(viewwindowx + viewwidth, viewwindowy - 4,
- W_CacheLumpName("bordtr", PU_CACHE));
+ W_CacheLumpName(DEH_String("bordtr"), PU_CACHE));
}
}
diff --git a/src/heretic/r_plane.c b/src/heretic/r_plane.c
index e35e2931..cc86b118 100644
--- a/src/heretic/r_plane.c
+++ b/src/heretic/r_plane.c
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include "doomdef.h"
+#include "deh_str.h"
#include "i_system.h"
#include "r_local.h"
@@ -90,7 +91,7 @@ fixed_t cachedystep[SCREENHEIGHT];
void R_InitSkyMap(void)
{
- skyflatnum = R_FlatNumForName("F_SKY1");
+ skyflatnum = R_FlatNumForName(DEH_String("F_SKY1"));
skytexturemid = 200 * FRACUNIT;
skyiscale = FRACUNIT;
}
diff --git a/src/heretic/r_things.c b/src/heretic/r_things.c
index 6302303e..e5ff4b4b 100644
--- a/src/heretic/r_things.c
+++ b/src/heretic/r_things.c
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
#include "doomdef.h"
+#include "deh_str.h"
#include "i_swap.h"
#include "i_system.h"
#include "r_local.h"
@@ -154,7 +155,7 @@ void R_InstallSpriteLump(int lump, unsigned frame, unsigned rotation,
void R_InitSpriteDefs(char **namelist)
{
char **check;
- int i, l, intname, frame, rotation;
+ int i, l, frame, rotation;
int start, end;
// count the number of sprite names
@@ -176,17 +177,16 @@ void R_InitSpriteDefs(char **namelist)
// Just compare 4 characters as ints
for (i = 0; i < numsprites; i++)
{
- spritename = namelist[i];
+ spritename = DEH_String(namelist[i]);
memset(sprtemp, -1, sizeof(sprtemp));
maxframe = -1;
- intname = *(int *) namelist[i];
//
// scan the lumps, filling in the frames for whatever is found
//
for (l = start + 1; l < end; l++)
- if (*(int *) lumpinfo[l].name == intname)
+ if (!strncasecmp(lumpinfo[l].name, spritename, 4))
{
frame = lumpinfo[l].name[4] - 'A';
rotation = lumpinfo[l].name[5] - '0';
@@ -209,7 +209,7 @@ void R_InitSpriteDefs(char **namelist)
if (gamemode == shareware)
continue;
I_Error("R_InitSprites: No lumps found for sprite %s",
- namelist[i]);
+ spritename);
}
maxframe++;
@@ -219,7 +219,7 @@ void R_InitSpriteDefs(char **namelist)
{
case -1: // no rotations were found for that frame at all
I_Error("R_InitSprites: No patches found for %s frame %c",
- namelist[i], frame + 'A');
+ spritename, frame + 'A');
case 0: // only the first rotation is needed
break;
@@ -228,7 +228,7 @@ void R_InitSpriteDefs(char **namelist)
if (sprtemp[frame].lump[rotation] == -1)
I_Error
("R_InitSprites: Sprite %s frame %c is missing rotations",
- namelist[i], frame + 'A');
+ spritename, frame + 'A');
}
}
diff --git a/src/heretic/s_sound.c b/src/heretic/s_sound.c
index bdd24594..73942201 100644
--- a/src/heretic/s_sound.c
+++ b/src/heretic/s_sound.c
@@ -33,6 +33,8 @@
#include "r_local.h"
#include "p_local.h"
+#include "sounds.h"
+
#include "w_wad.h"
#include "z_zone.h"
@@ -55,9 +57,6 @@ int mus_lumpnum;
void *mus_sndptr;
byte *soundCurve;
-extern sfxinfo_t S_sfx[];
-extern musicinfo_t S_music[];
-
int snd_MaxVolume = 10;
int snd_MusicVolume = 10;
int snd_Channels = 16;
@@ -529,7 +528,7 @@ void S_Init(void)
{
snd_Channels = 8;
}
- I_SetMusicVolume(snd_MusicVolume);
+ I_SetMusicVolume(snd_MusicVolume * 8);
S_SetMaxVolume(true);
I_AtExit(S_ShutDown, true);
@@ -550,8 +549,16 @@ void S_GetChannelInfo(SoundInfo_t * s)
c->priority = channel[i].priority;
c->name = S_sfx[c->id].name;
c->mo = channel[i].mo;
- c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy)
- >> FRACBITS;
+
+ if (c->mo != NULL)
+ {
+ c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy)
+ >> FRACBITS;
+ }
+ else
+ {
+ c->distance = 0;
+ }
}
}
@@ -579,7 +586,7 @@ void S_SetMaxVolume(boolean fullprocess)
static boolean musicPaused;
void S_SetMusicVolume(void)
{
- I_SetMusicVolume(snd_MusicVolume);
+ I_SetMusicVolume(snd_MusicVolume * 8);
if (snd_MusicVolume == 0)
{
I_PauseSong();
diff --git a/src/heretic/sb_bar.c b/src/heretic/sb_bar.c
index 77bd40c2..51bd3b9c 100644
--- a/src/heretic/sb_bar.c
+++ b/src/heretic/sb_bar.c
@@ -25,6 +25,7 @@
// SB_bar.c
#include "doomdef.h"
+#include "deh_str.h"
#include "i_video.h"
#include "m_cheat.h"
#include "m_misc.h"
@@ -196,53 +197,53 @@ void SB_Init(void)
int i;
int startLump;
- PatchLTFACE = W_CacheLumpName("LTFACE", PU_STATIC);
- PatchRTFACE = W_CacheLumpName("RTFACE", PU_STATIC);
- PatchBARBACK = W_CacheLumpName("BARBACK", PU_STATIC);
- PatchINVBAR = W_CacheLumpName("INVBAR", PU_STATIC);
- PatchCHAIN = W_CacheLumpName("CHAIN", PU_STATIC);
+ PatchLTFACE = W_CacheLumpName(DEH_String("LTFACE"), PU_STATIC);
+ PatchRTFACE = W_CacheLumpName(DEH_String("RTFACE"), PU_STATIC);
+ PatchBARBACK = W_CacheLumpName(DEH_String("BARBACK"), PU_STATIC);
+ PatchINVBAR = W_CacheLumpName(DEH_String("INVBAR"), PU_STATIC);
+ PatchCHAIN = W_CacheLumpName(DEH_String("CHAIN"), PU_STATIC);
if (deathmatch)
{
- PatchSTATBAR = W_CacheLumpName("STATBAR", PU_STATIC);
+ PatchSTATBAR = W_CacheLumpName(DEH_String("STATBAR"), PU_STATIC);
}
else
{
- PatchSTATBAR = W_CacheLumpName("LIFEBAR", PU_STATIC);
+ PatchSTATBAR = W_CacheLumpName(DEH_String("LIFEBAR"), PU_STATIC);
}
if (!netgame)
{ // single player game uses red life gem
- PatchLIFEGEM = W_CacheLumpName("LIFEGEM2", PU_STATIC);
+ PatchLIFEGEM = W_CacheLumpName(DEH_String("LIFEGEM2"), PU_STATIC);
}
else
{
- PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName("LIFEGEM0")
+ PatchLIFEGEM = W_CacheLumpNum(W_GetNumForName(DEH_String("LIFEGEM0"))
+ consoleplayer, PU_STATIC);
}
- PatchLTFCTOP = W_CacheLumpName("LTFCTOP", PU_STATIC);
- PatchRTFCTOP = W_CacheLumpName("RTFCTOP", PU_STATIC);
- PatchSELECTBOX = W_CacheLumpName("SELECTBOX", PU_STATIC);
- PatchINVLFGEM1 = W_CacheLumpName("INVGEML1", PU_STATIC);
- PatchINVLFGEM2 = W_CacheLumpName("INVGEML2", PU_STATIC);
- PatchINVRTGEM1 = W_CacheLumpName("INVGEMR1", PU_STATIC);
- PatchINVRTGEM2 = W_CacheLumpName("INVGEMR2", PU_STATIC);
- PatchBLACKSQ = W_CacheLumpName("BLACKSQ", PU_STATIC);
- PatchARMCLEAR = W_CacheLumpName("ARMCLEAR", PU_STATIC);
- PatchCHAINBACK = W_CacheLumpName("CHAINBACK", PU_STATIC);
- startLump = W_GetNumForName("IN0");
+ PatchLTFCTOP = W_CacheLumpName(DEH_String("LTFCTOP"), PU_STATIC);
+ PatchRTFCTOP = W_CacheLumpName(DEH_String("RTFCTOP"), PU_STATIC);
+ PatchSELECTBOX = W_CacheLumpName(DEH_String("SELECTBOX"), PU_STATIC);
+ PatchINVLFGEM1 = W_CacheLumpName(DEH_String("INVGEML1"), PU_STATIC);
+ PatchINVLFGEM2 = W_CacheLumpName(DEH_String("INVGEML2"), PU_STATIC);
+ PatchINVRTGEM1 = W_CacheLumpName(DEH_String("INVGEMR1"), PU_STATIC);
+ PatchINVRTGEM2 = W_CacheLumpName(DEH_String("INVGEMR2"), PU_STATIC);
+ PatchBLACKSQ = W_CacheLumpName(DEH_String("BLACKSQ"), PU_STATIC);
+ PatchARMCLEAR = W_CacheLumpName(DEH_String("ARMCLEAR"), PU_STATIC);
+ PatchCHAINBACK = W_CacheLumpName(DEH_String("CHAINBACK"), PU_STATIC);
+ startLump = W_GetNumForName(DEH_String("IN0"));
for (i = 0; i < 10; i++)
{
PatchINumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC);
}
- PatchNEGATIVE = W_CacheLumpName("NEGNUM", PU_STATIC);
- FontBNumBase = W_GetNumForName("FONTB16");
- startLump = W_GetNumForName("SMALLIN0");
+ PatchNEGATIVE = W_CacheLumpName(DEH_String("NEGNUM"), PU_STATIC);
+ FontBNumBase = W_GetNumForName(DEH_String("FONTB16"));
+ startLump = W_GetNumForName(DEH_String("SMALLIN0"));
for (i = 0; i < 10; i++)
{
PatchSmNumbers[i] = W_CacheLumpNum(startLump + i, PU_STATIC);
}
- playpalette = W_GetNumForName("PLAYPAL");
- spinbooklump = W_GetNumForName("SPINBK0");
- spinflylump = W_GetNumForName("SPFLY0");
+ playpalette = W_GetNumForName(DEH_String("PLAYPAL"));
+ spinbooklump = W_GetNumForName(DEH_String("SPINBK0"));
+ spinflylump = W_GetNumForName(DEH_String("SPFLY0"));
}
//---------------------------------------------------------------------------
@@ -311,7 +312,7 @@ static void DrINumber(signed int val, int x, int y)
{
if (val < -9)
{
- V_DrawPatch(x + 1, y + 1, W_CacheLumpName("LAME", PU_CACHE));
+ V_DrawPatch(x + 1, y + 1, W_CacheLumpName(DEH_String("LAME"), PU_CACHE));
}
else
{
@@ -458,7 +459,7 @@ static void DrawSoundInfo(void)
if (leveltime & 16)
{
- MN_DrTextA("*** SOUND DEBUG INFO ***", xPos[0], 20);
+ MN_DrTextA(DEH_String("*** SOUND DEBUG INFO ***"), xPos[0], 20);
}
S_GetChannelInfo(&s);
if (s.channelCount == 0)
@@ -466,13 +467,13 @@ static void DrawSoundInfo(void)
return;
}
x = 0;
- MN_DrTextA("NAME", xPos[x++], 30);
- MN_DrTextA("MO.T", xPos[x++], 30);
- MN_DrTextA("MO.X", xPos[x++], 30);
- MN_DrTextA("MO.Y", xPos[x++], 30);
- MN_DrTextA("ID", xPos[x++], 30);
- MN_DrTextA("PRI", xPos[x++], 30);
- MN_DrTextA("DIST", xPos[x++], 30);
+ MN_DrTextA(DEH_String("NAME"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("MO.T"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("MO.X"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("MO.Y"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("ID"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("PRI"), xPos[x++], 30);
+ MN_DrTextA(DEH_String("DIST"), xPos[x++], 30);
for (i = 0; i < s.channelCount; i++)
{
c = &s.chan[i];
@@ -480,7 +481,7 @@ static void DrawSoundInfo(void)
y = 40 + i * 10;
if (c->mo == NULL)
{ // Channel is unused
- MN_DrTextA("------", xPos[0], y);
+ MN_DrTextA(DEH_String("------"), xPos[0], y);
continue;
}
sprintf(text, "%s", c->name);
@@ -570,8 +571,10 @@ void SB_Drawer(void)
V_DrawPatch(0, 158, PatchBARBACK);
if (players[consoleplayer].cheats & CF_GODMODE)
{
- V_DrawPatch(16, 167, W_CacheLumpName("GOD1", PU_CACHE));
- V_DrawPatch(287, 167, W_CacheLumpName("GOD2", PU_CACHE));
+ V_DrawPatch(16, 167,
+ W_CacheLumpName(DEH_String("GOD1"), PU_CACHE));
+ V_DrawPatch(287, 167,
+ W_CacheLumpName(DEH_String("GOD2"), PU_CACHE));
}
oldhealth = -1;
}
@@ -776,8 +779,10 @@ void DrawMainBar(void)
if (ArtifactFlash)
{
V_DrawPatch(180, 161, PatchBLACKSQ);
- V_DrawPatch(182, 161, W_CacheLumpNum(W_GetNumForName("useartia")
- + ArtifactFlash - 1, PU_CACHE));
+
+ temp = W_GetNumForName(DEH_String("useartia")) + ArtifactFlash - 1;
+
+ V_DrawPatch(182, 161, W_CacheLumpNum(temp, PU_CACHE));
ArtifactFlash--;
oldarti = -1; // so that the correct artifact fills in after the flash
UpdateState |= I_STATBAR;
@@ -789,7 +794,7 @@ void DrawMainBar(void)
if (CPlayer->readyArtifact > 0)
{
V_DrawPatch(179, 160,
- W_CacheLumpName(patcharti[CPlayer->readyArtifact],
+ W_CacheLumpName(DEH_String(patcharti[CPlayer->readyArtifact]),
PU_CACHE));
DrSmallNumber(CPlayer->inventory[inv_ptr].count, 201, 182);
}
@@ -839,15 +844,15 @@ void DrawMainBar(void)
{
if (CPlayer->keys[key_yellow])
{
- V_DrawPatch(153, 164, W_CacheLumpName("ykeyicon", PU_CACHE));
+ V_DrawPatch(153, 164, W_CacheLumpName(DEH_String("ykeyicon"), PU_CACHE));
}
if (CPlayer->keys[key_green])
{
- V_DrawPatch(153, 172, W_CacheLumpName("gkeyicon", PU_CACHE));
+ V_DrawPatch(153, 172, W_CacheLumpName(DEH_String("gkeyicon"), PU_CACHE));
}
if (CPlayer->keys[key_blue])
{
- V_DrawPatch(153, 180, W_CacheLumpName("bkeyicon", PU_CACHE));
+ V_DrawPatch(153, 180, W_CacheLumpName(DEH_String("bkeyicon"), PU_CACHE));
}
oldkeys = playerkeys;
UpdateState |= I_STATBAR;
@@ -861,7 +866,7 @@ void DrawMainBar(void)
{
DrINumber(temp, 109, 162);
V_DrawPatch(111, 172,
- W_CacheLumpName(ammopic[CPlayer->readyweapon - 1],
+ W_CacheLumpName(DEH_String(ammopic[CPlayer->readyweapon - 1]),
PU_CACHE));
}
oldammo = temp;
@@ -887,6 +892,7 @@ void DrawMainBar(void)
void DrawInventoryBar(void)
{
+ char *patch;
int i;
int x;
@@ -899,10 +905,9 @@ void DrawInventoryBar(void)
if (CPlayer->inventorySlotNum > x + i
&& CPlayer->inventory[x + i].type != arti_none)
{
- V_DrawPatch(50 + i * 31, 160,
- W_CacheLumpName(patcharti
- [CPlayer->inventory[x + i].type],
- PU_CACHE));
+ patch = DEH_String(patcharti[CPlayer->inventory[x + i].type]);
+
+ V_DrawPatch(50 + i * 31, 160, W_CacheLumpName(patch, PU_CACHE));
DrSmallNumber(CPlayer->inventory[x + i].count, 69 + i * 31, 182);
}
}
@@ -921,6 +926,7 @@ void DrawInventoryBar(void)
void DrawFullScreenStuff(void)
{
+ char *patch;
int i;
int x;
int temp;
@@ -950,10 +956,9 @@ void DrawFullScreenStuff(void)
{
if (CPlayer->readyArtifact > 0)
{
- V_DrawTLPatch(286, 170, W_CacheLumpName("ARTIBOX", PU_CACHE));
- V_DrawPatch(286, 170,
- W_CacheLumpName(patcharti[CPlayer->readyArtifact],
- PU_CACHE));
+ patch = DEH_String(patcharti[CPlayer->readyArtifact]);
+ V_DrawTLPatch(286, 170, W_CacheLumpName(DEH_String("ARTIBOX"), PU_CACHE));
+ V_DrawPatch(286, 170, W_CacheLumpName(patch, PU_CACHE));
DrSmallNumber(CPlayer->inventory[inv_ptr].count, 307, 192);
}
}
@@ -962,15 +967,14 @@ void DrawFullScreenStuff(void)
x = inv_ptr - curpos;
for (i = 0; i < 7; i++)
{
- V_DrawTLPatch(50 + i * 31, 168, W_CacheLumpName("ARTIBOX",
- PU_CACHE));
+ V_DrawTLPatch(50 + i * 31, 168,
+ W_CacheLumpName(DEH_String("ARTIBOX"), PU_CACHE));
if (CPlayer->inventorySlotNum > x + i
&& CPlayer->inventory[x + i].type != arti_none)
{
+ patch = DEH_String(patcharti[CPlayer->inventory[x + i].type]);
V_DrawPatch(50 + i * 31, 168,
- W_CacheLumpName(patcharti
- [CPlayer->inventory[x + i].type],
- PU_CACHE));
+ W_CacheLumpName(patch, PU_CACHE));
DrSmallNumber(CPlayer->inventory[x + i].count, 69 + i * 31,
190);
}
@@ -1051,11 +1055,11 @@ static void CheatGodFunc(player_t * player, Cheat_t * cheat)
player->cheats ^= CF_GODMODE;
if (player->cheats & CF_GODMODE)
{
- P_SetMessage(player, TXT_CHEATGODON, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATGODON), false);
}
else
{
- P_SetMessage(player, TXT_CHEATGODOFF, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATGODOFF), false);
}
SB_state = -1;
}
@@ -1065,11 +1069,11 @@ static void CheatNoClipFunc(player_t * player, Cheat_t * cheat)
player->cheats ^= CF_NOCLIP;
if (player->cheats & CF_NOCLIP)
{
- P_SetMessage(player, TXT_CHEATNOCLIPON, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATNOCLIPON), false);
}
else
{
- P_SetMessage(player, TXT_CHEATNOCLIPOFF, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATNOCLIPOFF), false);
}
}
@@ -1102,7 +1106,7 @@ static void CheatWeaponsFunc(player_t * player, Cheat_t * cheat)
{
player->ammo[i] = player->maxammo[i];
}
- P_SetMessage(player, TXT_CHEATWEAPONS, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATWEAPONS), false);
}
static void CheatPowerFunc(player_t * player, Cheat_t * cheat)
@@ -1110,12 +1114,12 @@ static void CheatPowerFunc(player_t * player, Cheat_t * cheat)
if (player->powers[pw_weaponlevel2])
{
player->powers[pw_weaponlevel2] = 0;
- P_SetMessage(player, TXT_CHEATPOWEROFF, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATPOWEROFF), false);
}
else
{
P_UseArtifact(player, arti_tomeofpower);
- P_SetMessage(player, TXT_CHEATPOWERON, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATPOWERON), false);
}
}
@@ -1129,7 +1133,7 @@ static void CheatHealthFunc(player_t * player, Cheat_t * cheat)
{
player->health = player->mo->health = MAXHEALTH;
}
- P_SetMessage(player, TXT_CHEATHEALTH, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATHEALTH), false);
}
static void CheatKeysFunc(player_t * player, Cheat_t * cheat)
@@ -1140,7 +1144,7 @@ static void CheatKeysFunc(player_t * player, Cheat_t * cheat)
player->keys[key_green] = true;
player->keys[key_blue] = true;
playerkeys = 7; // Key refresh flags
- P_SetMessage(player, TXT_CHEATKEYS, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATKEYS), false);
}
static void CheatSoundFunc(player_t * player, Cheat_t * cheat)
@@ -1148,11 +1152,11 @@ static void CheatSoundFunc(player_t * player, Cheat_t * cheat)
DebugSound = !DebugSound;
if (DebugSound)
{
- P_SetMessage(player, TXT_CHEATSOUNDON, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATSOUNDON), false);
}
else
{
- P_SetMessage(player, TXT_CHEATSOUNDOFF, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATSOUNDOFF), false);
}
}
@@ -1161,11 +1165,11 @@ static void CheatTickerFunc(player_t * player, Cheat_t * cheat)
DisplayTicker = !DisplayTicker;
if (DisplayTicker)
{
- P_SetMessage(player, TXT_CHEATTICKERON, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATTICKERON), false);
}
else
{
- P_SetMessage(player, TXT_CHEATTICKEROFF, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATTICKEROFF), false);
}
I_DisplayFPSDots(DisplayTicker);
@@ -1173,12 +1177,12 @@ static void CheatTickerFunc(player_t * player, Cheat_t * cheat)
static void CheatArtifact1Func(player_t * player, Cheat_t * cheat)
{
- P_SetMessage(player, TXT_CHEATARTIFACTS1, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS1), false);
}
static void CheatArtifact2Func(player_t * player, Cheat_t * cheat)
{
- P_SetMessage(player, TXT_CHEATARTIFACTS2, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS2), false);
}
static void CheatArtifact3Func(player_t * player, Cheat_t * cheat)
@@ -1206,7 +1210,7 @@ static void CheatArtifact3Func(player_t * player, Cheat_t * cheat)
P_GiveArtifact(player, i, NULL);
}
}
- P_SetMessage(player, TXT_CHEATARTIFACTS3, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS3), false);
}
else if (type > arti_none && type < NUMARTIFACTS
&& count > 0 && count < 10)
@@ -1214,18 +1218,18 @@ static void CheatArtifact3Func(player_t * player, Cheat_t * cheat)
if (gamemode == shareware
&& (type == arti_superhealth || type == arti_teleport))
{
- P_SetMessage(player, TXT_CHEATARTIFACTSFAIL, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTSFAIL), false);
return;
}
for (i = 0; i < count; i++)
{
P_GiveArtifact(player, type, NULL);
}
- P_SetMessage(player, TXT_CHEATARTIFACTS3, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTS3), false);
}
else
{ // Bad input
- P_SetMessage(player, TXT_CHEATARTIFACTSFAIL, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATARTIFACTSFAIL), false);
}
}
@@ -1242,7 +1246,7 @@ static void CheatWarpFunc(player_t * player, Cheat_t * cheat)
if (D_ValidEpisodeMap(gamemission, gamemode, episode, map))
{
G_DeferedInitNew(gameskill, episode, map);
- P_SetMessage(player, TXT_CHEATWARP, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATWARP), false);
}
}
@@ -1254,19 +1258,19 @@ static void CheatChickenFunc(player_t * player, Cheat_t * cheat)
{
if (P_UndoPlayerChicken(player))
{
- P_SetMessage(player, TXT_CHEATCHICKENOFF, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATCHICKENOFF), false);
}
}
else if (P_ChickenMorphPlayer(player))
{
- P_SetMessage(player, TXT_CHEATCHICKENON, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATCHICKENON), false);
}
}
static void CheatMassacreFunc(player_t * player, Cheat_t * cheat)
{
P_Massacre();
- P_SetMessage(player, TXT_CHEATMASSACRE, false);
+ P_SetMessage(player, DEH_String(TXT_CHEATMASSACRE), false);
}
static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat)
@@ -1281,11 +1285,11 @@ static void CheatIDKFAFunc(player_t * player, Cheat_t * cheat)
player->weaponowned[i] = false;
}
player->pendingweapon = wp_staff;
- P_SetMessage(player, TXT_CHEATIDKFA, true);
+ P_SetMessage(player, DEH_String(TXT_CHEATIDKFA), true);
}
static void CheatIDDQDFunc(player_t * player, Cheat_t * cheat)
{
P_DamageMobj(player->mo, NULL, player->mo, 10000);
- P_SetMessage(player, TXT_CHEATIDDQD, true);
+ P_SetMessage(player, DEH_String(TXT_CHEATIDDQD), true);
}
diff --git a/src/heretic/sounds.h b/src/heretic/sounds.h
index 707185c0..e50a6ad6 100644
--- a/src/heretic/sounds.h
+++ b/src/heretic/sounds.h
@@ -27,6 +27,8 @@
#ifndef __SOUNDSH__
#define __SOUNDSH__
+#include "i_sound.h"
+
#define MAX_SND_DIST 1600
#define MAX_CHANNELS 16
@@ -291,4 +293,7 @@ typedef enum
NUMSFX
} sfxenum_t;
+extern sfxinfo_t S_sfx[];
+extern musicinfo_t S_music[];
+
#endif
diff --git a/src/hexen/.gitignore b/src/hexen/.gitignore
index d7e732ad..d4e88e5a 100644
--- a/src/hexen/.gitignore
+++ b/src/hexen/.gitignore
@@ -1,7 +1,5 @@
Makefile
Makefile.in
.deps
-*.rc
-chocolate-doom
-chocolate-server
-*.exe
+tags
+TAGS
diff --git a/src/hexen/h2_main.c b/src/hexen/h2_main.c
index ef223c0e..abc58f15 100644
--- a/src/hexen/h2_main.c
+++ b/src/hexen/h2_main.c
@@ -46,6 +46,7 @@
#include "m_controls.h"
#include "p_local.h"
#include "v_video.h"
+#include "w_main.h"
// MACROS ------------------------------------------------------------------
@@ -88,7 +89,6 @@ static void PageDrawer(void);
static void HandleArgs(void);
static void CheckRecordFrom(void);
static void DrawAndBlit(void);
-static void ExecOptionFILE(char **args, int tag);
static void ExecOptionSCRIPTS(char **args, int tag);
static void ExecOptionSKILL(char **args, int tag);
static void ExecOptionPLAYDEMO(char **args, int tag);
@@ -133,7 +133,6 @@ static int pagetic;
static char *pagename;
static execOpt_t ExecOptions[] = {
- {"-file", ExecOptionFILE, 1, 0},
{"-scripts", ExecOptionSCRIPTS, 1, 0},
{"-skill", ExecOptionSKILL, 1, 0},
{"-playdemo", ExecOptionPLAYDEMO, 1, 0},
@@ -157,6 +156,7 @@ void D_BindVariables(void)
M_BindMapControls();
M_BindMenuControls();
M_BindWeaponControls();
+ M_BindChatControls(MAXPLAYERS);
M_BindHereticControls();
M_BindHexenControls();
@@ -422,6 +422,9 @@ static void HandleArgs(void)
cmdfrag = M_ParmExists("-cmdfrag");
+ // Check WAD file command line options
+ W_ParseCommandLine();
+
// Process command line options
for (opt = ExecOptions; opt->name != NULL; opt++)
{
@@ -485,27 +488,6 @@ static void ExecOptionSKILL(char **args, int tag)
//==========================================================================
//
-// ExecOptionFILE
-//
-//==========================================================================
-
-static void ExecOptionFILE(char **args, int tag)
-{
- char *filename;
- int p;
-
- p = M_CheckParm("-file");
- while (++p != myargc && myargv[p][0] != '-')
- {
- filename = D_TryFindWADByName(myargv[p]);
-
- D_AddFile(filename);
- }
-}
-
-
-//==========================================================================
-//
// ExecOptionPLAYDEMO
//
//==========================================================================
diff --git a/src/hexen/mn_menu.c b/src/hexen/mn_menu.c
index 09a8f1ea..9f37df66 100644
--- a/src/hexen/mn_menu.c
+++ b/src/hexen/mn_menu.c
@@ -679,6 +679,32 @@ static void DrawSaveMenu(void)
DrawFileSlots(&SaveMenu);
}
+static boolean ReadDescriptionForSlot(int slot, char *description)
+{
+ FILE *fp;
+ boolean found;
+ char name[100];
+ char versionText[HXS_VERSION_TEXT_LENGTH];
+
+ sprintf(name, "%shex%d.hxs", SavePath, slot);
+
+ fp = fopen(name, "rb");
+
+ if (fp == NULL)
+ {
+ return false;
+ }
+
+ found = fread(description, HXS_DESCRIPTION_LENGTH, 1, fp) == 1
+ && fread(versionText, HXS_VERSION_TEXT_LENGTH, 1, fp) == 1;
+
+ found = found && strcmp(versionText, HXS_VERSION_TEXT) == 0;
+
+ fclose(fp);
+
+ return found;
+}
+
//===========================================================================
//
// MN_LoadSlotText
@@ -689,29 +715,12 @@ static void DrawSaveMenu(void)
void MN_LoadSlotText(void)
{
- int slot;
- FILE *fp;
- char name[100];
- char versionText[HXS_VERSION_TEXT_LENGTH];
char description[HXS_DESCRIPTION_LENGTH];
- boolean found;
+ int slot;
for (slot = 0; slot < 6; slot++)
{
- found = false;
- sprintf(name, "%shex%d.hxs", SavePath, slot);
- fp = fopen(name, "rb");
- if (fp)
- {
- fread(description, HXS_DESCRIPTION_LENGTH, 1, fp);
- fread(versionText, HXS_VERSION_TEXT_LENGTH, 1, fp);
- fclose(fp);
- if (!strcmp(versionText, HXS_VERSION_TEXT))
- {
- found = true;
- }
- }
- if (found)
+ if (ReadDescriptionForSlot(slot, description))
{
memcpy(SlotText[slot], description, SLOTTEXTLEN);
SlotStatus[slot] = 1;
diff --git a/src/hexen/p_acs.c b/src/hexen/p_acs.c
index 618bbd05..9ca9f6af 100644
--- a/src/hexen/p_acs.c
+++ b/src/hexen/p_acs.c
@@ -509,7 +509,7 @@ static boolean AddToACSStore(int map, int number, byte * args)
}
ACSStore[index].map = map;
ACSStore[index].script = number;
- *((int *) ACSStore[index].args) = *((int *) args);
+ memcpy(ACSStore[index].args, args, sizeof(int));
return true;
}
diff --git a/src/hexen/p_spec.c b/src/hexen/p_spec.c
index ca0bbfb8..03c98cbc 100644
--- a/src/hexen/p_spec.c
+++ b/src/hexen/p_spec.c
@@ -245,6 +245,8 @@ fixed_t P_FindNextHighestFloor(sector_t * sec, int currentheight)
fixed_t height = currentheight;
fixed_t heightlist[20]; // 20 adjoining sectors max!
+ heightlist[0] = 0;
+
for (i = 0, h = 0; i < sec->linecount; i++)
{
check = sec->lines[i];
diff --git a/src/hexen/r_things.c b/src/hexen/r_things.c
index 0517fd49..aeba11c4 100644
--- a/src/hexen/r_things.c
+++ b/src/hexen/r_things.c
@@ -158,7 +158,7 @@ void R_InstallSpriteLump(int lump, unsigned frame, unsigned rotation,
void R_InitSpriteDefs(char **namelist)
{
char **check;
- int i, l, intname, frame, rotation;
+ int i, l, frame, rotation;
int start, end;
// count the number of sprite names
@@ -184,13 +184,12 @@ void R_InitSpriteDefs(char **namelist)
memset(sprtemp, -1, sizeof(sprtemp));
maxframe = -1;
- intname = *(int *) namelist[i];
//
// scan the lumps, filling in the frames for whatever is found
//
for (l = start + 1; l < end; l++)
- if (*(int *) lumpinfo[l].name == intname)
+ if (!strncmp(lumpinfo[l].name, namelist[i], 4))
{
frame = lumpinfo[l].name[4] - 'A';
rotation = lumpinfo[l].name[5] - '0';
diff --git a/src/hexen/s_sound.c b/src/hexen/s_sound.c
index fdd01ba5..f11e4ee9 100644
--- a/src/hexen/s_sound.c
+++ b/src/hexen/s_sound.c
@@ -736,7 +736,7 @@ void S_Init(void)
{
snd_Channels = 8;
}
- I_SetMusicVolume(snd_MusicVolume);
+ I_SetMusicVolume(snd_MusicVolume * 8);
I_AtExit(S_ShutDown, true);
@@ -787,8 +787,16 @@ void S_GetChannelInfo(SoundInfo_t * s)
c->priority = Channel[i].priority;
c->name = S_sfx[c->id].name;
c->mo = Channel[i].mo;
- c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy)
- >> FRACBITS;
+
+ if (c->mo != NULL)
+ {
+ c->distance = P_AproxDistance(c->mo->x - viewx, c->mo->y - viewy)
+ >> FRACBITS;
+ }
+ else
+ {
+ c->distance = 0;
+ }
}
}
@@ -829,7 +837,7 @@ void S_SetMusicVolume(void)
}
else
{
- I_SetMusicVolume(snd_MusicVolume);
+ I_SetMusicVolume(snd_MusicVolume * 8);
}
if (snd_MusicVolume == 0)
{
diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c
new file mode 100644
index 00000000..e7a42e83
--- /dev/null
+++ b/src/i_oplmusic.c
@@ -0,0 +1,1464 @@
+// 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 interface for music.
+//
+//-----------------------------------------------------------------------------
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memio.h"
+#include "mus2mid.h"
+
+#include "deh_main.h"
+#include "i_sound.h"
+#include "i_swap.h"
+#include "m_misc.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+#include "opl.h"
+#include "midifile.h"
+
+// #define OPL_MIDI_DEBUG
+
+#define MAXMIDLENGTH (96 * 1024)
+#define GENMIDI_NUM_INSTRS 128
+
+#define GENMIDI_HEADER "#OPL_II#"
+#define GENMIDI_FLAG_FIXED 0x0001 /* fixed pitch */
+#define GENMIDI_FLAG_2VOICE 0x0004 /* double voice (OPL3) */
+
+typedef struct
+{
+ byte tremolo;
+ byte attack;
+ byte sustain;
+ byte waveform;
+ byte scale;
+ byte level;
+} PACKEDATTR genmidi_op_t;
+
+typedef struct
+{
+ genmidi_op_t modulator;
+ byte feedback;
+ genmidi_op_t carrier;
+ byte unused;
+ short base_note_offset;
+} PACKEDATTR genmidi_voice_t;
+
+typedef struct
+{
+ unsigned short flags;
+ byte fine_tuning;
+ byte fixed_note;
+
+ genmidi_voice_t voices[2];
+} PACKEDATTR genmidi_instr_t;
+
+// Data associated with a channel of a track that is currently playing.
+
+typedef struct
+{
+ // The instrument currently used for this track.
+
+ genmidi_instr_t *instrument;
+
+ // Volume level
+
+ int volume;
+
+ // Pitch bend value:
+
+ int bend;
+
+} opl_channel_data_t;
+
+// Data associated with a track that is currently playing.
+
+typedef struct
+{
+ // Data for each channel.
+
+ opl_channel_data_t channels[MIDI_CHANNELS_PER_TRACK];
+
+ // Track iterator used to read new events.
+
+ midi_track_iter_t *iter;
+
+ // Tempo control variables
+
+ unsigned int ticks_per_beat;
+ unsigned int ms_per_beat;
+} opl_track_data_t;
+
+typedef struct opl_voice_s opl_voice_t;
+
+struct opl_voice_s
+{
+ // Index of this voice:
+ int index;
+
+ // The operators used by this voice:
+ int op1, op2;
+
+ // Currently-loaded instrument data
+ genmidi_instr_t *current_instr;
+
+ // The voice number in the instrument to use.
+ // This is normally set to zero; if this is a double voice
+ // instrument, it may be one.
+ unsigned int current_instr_voice;
+
+ // The channel currently using this voice.
+ opl_channel_data_t *channel;
+
+ // The midi key that this voice is playing.
+ unsigned int key;
+
+ // The note being played. This is normally the same as
+ // the key, but if the instrument is a fixed pitch
+ // instrument, it is different.
+ unsigned int note;
+
+ // The frequency value being used.
+ unsigned int freq;
+
+ // The volume of the note being played on this channel.
+ unsigned int note_volume;
+
+ // The current volume (register value) that has been set for this channel.
+ unsigned int reg_volume;
+
+ // Next in linked list; a voice is always either in the
+ // free list or the allocated list.
+ opl_voice_t *next;
+};
+
+// Operators used by the different voices.
+
+static const int voice_operators[2][OPL_NUM_VOICES] = {
+ { 0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12 },
+ { 0x03, 0x04, 0x05, 0x0b, 0x0c, 0x0d, 0x13, 0x14, 0x15 }
+};
+
+// Frequency values to use for each note.
+
+static const unsigned short frequency_curve[] = {
+
+ 0x133, 0x133, 0x134, 0x134, 0x135, 0x136, 0x136, 0x137, // -1
+ 0x137, 0x138, 0x138, 0x139, 0x139, 0x13a, 0x13b, 0x13b,
+ 0x13c, 0x13c, 0x13d, 0x13d, 0x13e, 0x13f, 0x13f, 0x140,
+ 0x140, 0x141, 0x142, 0x142, 0x143, 0x143, 0x144, 0x144,
+
+ 0x145, 0x146, 0x146, 0x147, 0x147, 0x148, 0x149, 0x149, // -2
+ 0x14a, 0x14a, 0x14b, 0x14c, 0x14c, 0x14d, 0x14d, 0x14e,
+ 0x14f, 0x14f, 0x150, 0x150, 0x151, 0x152, 0x152, 0x153,
+ 0x153, 0x154, 0x155, 0x155, 0x156, 0x157, 0x157, 0x158,
+
+ // These are used for the first seven MIDI note values:
+
+ 0x158, 0x159, 0x15a, 0x15a, 0x15b, 0x15b, 0x15c, 0x15d, // 0
+ 0x15d, 0x15e, 0x15f, 0x15f, 0x160, 0x161, 0x161, 0x162,
+ 0x162, 0x163, 0x164, 0x164, 0x165, 0x166, 0x166, 0x167,
+ 0x168, 0x168, 0x169, 0x16a, 0x16a, 0x16b, 0x16c, 0x16c,
+
+ 0x16d, 0x16e, 0x16e, 0x16f, 0x170, 0x170, 0x171, 0x172, // 1
+ 0x172, 0x173, 0x174, 0x174, 0x175, 0x176, 0x176, 0x177,
+ 0x178, 0x178, 0x179, 0x17a, 0x17a, 0x17b, 0x17c, 0x17c,
+ 0x17d, 0x17e, 0x17e, 0x17f, 0x180, 0x181, 0x181, 0x182,
+
+ 0x183, 0x183, 0x184, 0x185, 0x185, 0x186, 0x187, 0x188, // 2
+ 0x188, 0x189, 0x18a, 0x18a, 0x18b, 0x18c, 0x18d, 0x18d,
+ 0x18e, 0x18f, 0x18f, 0x190, 0x191, 0x192, 0x192, 0x193,
+ 0x194, 0x194, 0x195, 0x196, 0x197, 0x197, 0x198, 0x199,
+
+ 0x19a, 0x19a, 0x19b, 0x19c, 0x19d, 0x19d, 0x19e, 0x19f, // 3
+ 0x1a0, 0x1a0, 0x1a1, 0x1a2, 0x1a3, 0x1a3, 0x1a4, 0x1a5,
+ 0x1a6, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1a9, 0x1aa, 0x1ab,
+ 0x1ac, 0x1ad, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b0, 0x1b1,
+
+ 0x1b2, 0x1b3, 0x1b4, 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8, // 4
+ 0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, 0x1bc, 0x1bd, 0x1be,
+ 0x1bf, 0x1c0, 0x1c0, 0x1c1, 0x1c2, 0x1c3, 0x1c4, 0x1c4,
+ 0x1c5, 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1c9, 0x1ca, 0x1cb,
+
+ 0x1cc, 0x1cd, 0x1ce, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, // 5
+ 0x1d3, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d8,
+ 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df,
+ 0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e5, 0x1e6,
+
+ 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed, // 6
+ 0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5,
+ 0x1f6, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc,
+ 0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x201, 0x202, 0x203,
+
+ // First note of looped range used for all octaves:
+
+ 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, // 7
+ 0x20c, 0x20d, 0x20e, 0x20f, 0x210, 0x210, 0x211, 0x212,
+ 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a,
+ 0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222,
+
+ 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, // 8
+ 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232,
+ 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a,
+ 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, 0x241, 0x242,
+
+ 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, // 9
+ 0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253,
+ 0x254, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c,
+ 0x25d, 0x25e, 0x25f, 0x260, 0x262, 0x263, 0x264, 0x265,
+
+ 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, // 10
+ 0x26f, 0x270, 0x271, 0x272, 0x273, 0x275, 0x276, 0x277,
+ 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280,
+ 0x281, 0x282, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289,
+
+ 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x292, 0x293, // 11
+ 0x294, 0x295, 0x296, 0x298, 0x299, 0x29a, 0x29b, 0x29c,
+ 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6,
+ 0x2a7, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ae, 0x2af, 0x2b0,
+
+ 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba, // 12
+ 0x2bb, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c2, 0x2c3, 0x2c4,
+ 0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x2cb, 0x2cc, 0x2cd, 0x2ce,
+ 0x2d0, 0x2d1, 0x2d2, 0x2d4, 0x2d5, 0x2d6, 0x2d8, 0x2d9,
+
+ 0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, // 13
+ 0x2e5, 0x2e6, 0x2e8, 0x2e9, 0x2ea, 0x2ec, 0x2ed, 0x2ee,
+ 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9,
+ 0x2fb, 0x2fc, 0x2fd, 0x2ff, 0x300, 0x302, 0x303, 0x304,
+
+ 0x306, 0x307, 0x309, 0x30a, 0x30b, 0x30d, 0x30e, 0x310, // 14
+ 0x311, 0x312, 0x314, 0x315, 0x317, 0x318, 0x31a, 0x31b,
+ 0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327,
+ 0x328, 0x329, 0x32b, 0x32c, 0x32e, 0x32f, 0x331, 0x332,
+
+ 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e, // 15
+ 0x340, 0x341, 0x343, 0x344, 0x346, 0x347, 0x349, 0x34a,
+ 0x34c, 0x34d, 0x34f, 0x350, 0x352, 0x353, 0x355, 0x357,
+ 0x358, 0x35a, 0x35b, 0x35d, 0x35e, 0x360, 0x361, 0x363,
+
+ 0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, // 16
+ 0x371, 0x373, 0x374, 0x376, 0x378, 0x379, 0x37b, 0x37c,
+ 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389,
+ 0x38b, 0x38d, 0x38e, 0x390, 0x392, 0x393, 0x395, 0x397,
+
+ 0x398, 0x39a, 0x39c, 0x39d, 0x39f, 0x3a1, 0x3a2, 0x3a4, // 17
+ 0x3a6, 0x3a7, 0x3a9, 0x3ab, 0x3ac, 0x3ae, 0x3b0, 0x3b1,
+ 0x3b3, 0x3b5, 0x3b7, 0x3b8, 0x3ba, 0x3bc, 0x3bd, 0x3bf,
+ 0x3c1, 0x3c3, 0x3c4, 0x3c6, 0x3c8, 0x3ca, 0x3cb, 0x3cd,
+
+ // The last note has an incomplete range, and loops round back to
+ // the start. Note that the last value is actually a buffer overrun
+ // and does not fit with the other values.
+
+ 0x3cf, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3da, 0x3db, // 18
+ 0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e4, 0x3e6, 0x3e8, 0x3ea,
+ 0x3ec, 0x3ed, 0x3ef, 0x3f1, 0x3f3, 0x3f5, 0x3f6, 0x3f8,
+ 0x3fa, 0x3fc, 0x3fe, 0x36c,
+};
+
+// Mapping from MIDI volume level to OPL level value.
+
+static const unsigned int volume_mapping_table[] = {
+ 0, 1, 3, 5, 6, 8, 10, 11,
+ 13, 14, 16, 17, 19, 20, 22, 23,
+ 25, 26, 27, 29, 30, 32, 33, 34,
+ 36, 37, 39, 41, 43, 45, 47, 49,
+ 50, 52, 54, 55, 57, 59, 60, 61,
+ 63, 64, 66, 67, 68, 69, 71, 72,
+ 73, 74, 75, 76, 77, 79, 80, 81,
+ 82, 83, 84, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 92, 93, 94, 95,
+ 96, 96, 97, 98, 99, 99, 100, 101,
+ 101, 102, 103, 103, 104, 105, 105, 106,
+ 107, 107, 108, 109, 109, 110, 110, 111,
+ 112, 112, 113, 113, 114, 114, 115, 115,
+ 116, 117, 117, 118, 118, 119, 119, 120,
+ 120, 121, 121, 122, 122, 123, 123, 123,
+ 124, 124, 125, 125, 126, 126, 127, 127
+};
+
+static boolean music_initialized = false;
+
+//static boolean musicpaused = false;
+static int current_music_volume;
+
+// GENMIDI lump instrument data:
+
+static genmidi_instr_t *main_instrs;
+static genmidi_instr_t *percussion_instrs;
+
+// Voices:
+
+static opl_voice_t voices[OPL_NUM_VOICES];
+static opl_voice_t *voice_free_list;
+static opl_voice_t *voice_alloced_list;
+
+// Track data for playing tracks:
+
+static opl_track_data_t *tracks;
+static unsigned int num_tracks = 0;
+static unsigned int running_tracks = 0;
+static boolean song_looping;
+
+// Configuration file variable, containing the port number for the
+// adlib chip.
+
+int opl_io_port = 0x388;
+
+// Load instrument table from GENMIDI lump:
+
+static boolean LoadInstrumentTable(void)
+{
+ byte *lump;
+
+ lump = W_CacheLumpName("GENMIDI", PU_STATIC);
+
+ // Check header
+
+ if (strncmp((char *) lump, GENMIDI_HEADER, strlen(GENMIDI_HEADER)) != 0)
+ {
+ W_ReleaseLumpName("GENMIDI");
+
+ return false;
+ }
+
+ main_instrs = (genmidi_instr_t *) (lump + strlen(GENMIDI_HEADER));
+ percussion_instrs = main_instrs + GENMIDI_NUM_INSTRS;
+
+ return true;
+}
+
+// Get the next available voice from the freelist.
+
+static opl_voice_t *GetFreeVoice(void)
+{
+ opl_voice_t *result;
+
+ // None available?
+
+ if (voice_free_list == NULL)
+ {
+ return NULL;
+ }
+
+ // Remove from free list
+
+ result = voice_free_list;
+ voice_free_list = voice_free_list->next;
+
+ // Add to allocated list
+
+ result->next = voice_alloced_list;
+ voice_alloced_list = result;
+
+ return result;
+}
+
+// Remove a voice from the allocated voices list.
+
+static void RemoveVoiceFromAllocedList(opl_voice_t *voice)
+{
+ opl_voice_t **rover;
+
+ rover = &voice_alloced_list;
+
+ // Search the list until we find the voice, then remove it.
+
+ while (*rover != NULL)
+ {
+ if (*rover == voice)
+ {
+ *rover = voice->next;
+ voice->next = NULL;
+ break;
+ }
+
+ rover = &(*rover)->next;
+ }
+}
+
+// Release a voice back to the freelist.
+
+static void ReleaseVoice(opl_voice_t *voice)
+{
+ opl_voice_t **rover;
+
+ voice->channel = NULL;
+ voice->note = 0;
+
+ // Remove from alloced list.
+
+ RemoveVoiceFromAllocedList(voice);
+
+ // Search to the end of the freelist (This is how Doom behaves!)
+
+ rover = &voice_free_list;
+
+ while (*rover != NULL)
+ {
+ rover = &(*rover)->next;
+ }
+
+ *rover = voice;
+ voice->next = NULL;
+}
+
+// Load data to the specified operator
+
+static void LoadOperatorData(int operator, genmidi_op_t *data,
+ boolean max_level)
+{
+ int level;
+
+ // The scale and level fields must be combined for the level register.
+ // For the carrier wave we always set the maximum level.
+
+ level = (data->scale & 0xc0) | (data->level & 0x3f);
+
+ if (max_level)
+ {
+ level |= 0x3f;
+ }
+
+ OPL_WriteRegister(OPL_REGS_LEVEL + operator, level);
+ OPL_WriteRegister(OPL_REGS_TREMOLO + operator, data->tremolo);
+ OPL_WriteRegister(OPL_REGS_ATTACK + operator, data->attack);
+ OPL_WriteRegister(OPL_REGS_SUSTAIN + operator, data->sustain);
+ OPL_WriteRegister(OPL_REGS_WAVEFORM + operator, data->waveform);
+}
+
+// Set the instrument for a particular voice.
+
+static void SetVoiceInstrument(opl_voice_t *voice,
+ genmidi_instr_t *instr,
+ unsigned int instr_voice)
+{
+ genmidi_voice_t *data;
+ unsigned int modulating;
+
+ // Instrument already set for this channel?
+
+ if (voice->current_instr == instr
+ && voice->current_instr_voice == instr_voice)
+ {
+ return;
+ }
+
+ voice->current_instr = instr;
+ voice->current_instr_voice = instr_voice;
+
+ data = &instr->voices[instr_voice];
+
+ // Are we usind modulated feedback mode?
+
+ modulating = (data->feedback & 0x01) == 0;
+
+ // Doom loads the second operator first, then the first.
+ // The carrier is set to minimum volume until the voice volume
+ // is set in SetVoiceVolume (below). If we are not using
+ // modulating mode, we must set both to minimum volume.
+
+ LoadOperatorData(voice->op2, &data->carrier, true);
+ LoadOperatorData(voice->op1, &data->modulator, !modulating);
+
+ // Set feedback register that control the connection between the
+ // two operators. Turn on bits in the upper nybble; I think this
+ // is for OPL3, where it turns on channel A/B.
+
+ OPL_WriteRegister(OPL_REGS_FEEDBACK + voice->index,
+ data->feedback | 0x30);
+
+ // Hack to force a volume update.
+
+ voice->reg_volume = 999;
+}
+
+static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume)
+{
+ genmidi_voice_t *opl_voice;
+ unsigned int full_volume;
+ unsigned int op_volume;
+ unsigned int reg_volume;
+
+ voice->note_volume = volume;
+
+ opl_voice = &voice->current_instr->voices[voice->current_instr_voice];
+
+ // Multiply note volume and channel volume to get the actual volume.
+
+ full_volume = (volume_mapping_table[voice->note_volume]
+ * volume_mapping_table[voice->channel->volume]
+ * volume_mapping_table[current_music_volume]) / (127 * 127);
+
+ // The volume of each instrument can be controlled via GENMIDI:
+
+ op_volume = 0x3f - opl_voice->carrier.level;
+
+ // The volume value to use in the register:
+
+ reg_volume = (op_volume * full_volume) / 128;
+ reg_volume = (0x3f - reg_volume) | opl_voice->carrier.scale;
+
+ // Update the volume register(s) if necessary.
+
+ if (reg_volume != voice->reg_volume)
+ {
+ voice->reg_volume = reg_volume;
+
+ OPL_WriteRegister(OPL_REGS_LEVEL + voice->op2, reg_volume);
+
+ // If we are using non-modulated feedback mode, we must set the
+ // volume for both voices.
+ // Note that the same register volume value is written for
+ // both voices, always calculated from the carrier's level
+ // value.
+
+ if ((opl_voice->feedback & 0x01) != 0)
+ {
+ OPL_WriteRegister(OPL_REGS_LEVEL + voice->op1, reg_volume);
+ }
+ }
+}
+
+// Initialize the voice table and freelist
+
+static void InitVoices(void)
+{
+ int i;
+
+ // Start with an empty free list.
+
+ voice_free_list = NULL;
+
+ // Initialize each voice.
+
+ for (i=0; i<OPL_NUM_VOICES; ++i)
+ {
+ voices[i].index = i;
+ voices[i].op1 = voice_operators[0][i];
+ voices[i].op2 = voice_operators[1][i];
+ voices[i].current_instr = NULL;
+
+ // Add this voice to the freelist.
+
+ ReleaseVoice(&voices[i]);
+ }
+}
+
+// Set music volume (0 - 127)
+
+static void I_OPL_SetMusicVolume(int volume)
+{
+ unsigned int i;
+
+ // Internal state variable.
+
+ current_music_volume = volume;
+
+ // Update the volume of all voices.
+
+ for (i=0; i<OPL_NUM_VOICES; ++i)
+ {
+ if (voices[i].channel != NULL)
+ {
+ SetVoiceVolume(&voices[i], voices[i].note_volume);
+ }
+ }
+}
+
+static void VoiceKeyOff(opl_voice_t *voice)
+{
+ OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, voice->freq >> 8);
+}
+
+// Get the frequency that we should be using for a voice.
+
+static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event)
+{
+ opl_channel_data_t *channel;
+ unsigned int key;
+ unsigned int i;
+
+/*
+ printf("note off: channel %i, %i, %i\n",
+ event->data.channel.channel,
+ event->data.channel.param1,
+ event->data.channel.param2);
+*/
+
+ channel = &track->channels[event->data.channel.channel];
+ key = event->data.channel.param1;
+
+ // Turn off voices being used to play this key.
+ // If it is a double voice instrument there will be two.
+
+ for (i=0; i<OPL_NUM_VOICES; ++i)
+ {
+ if (voices[i].channel == channel && voices[i].key == key)
+ {
+ VoiceKeyOff(&voices[i]);
+
+ // Finished with this voice now.
+
+ ReleaseVoice(&voices[i]);
+ }
+ }
+}
+
+// Compare the priorities of channels, returning either -1, 0 or 1.
+
+static int CompareChannelPriorities(opl_channel_data_t *chan1,
+ opl_channel_data_t *chan2)
+{
+ // TODO ...
+
+ return 1;
+}
+
+// When all voices are in use, we must discard an existing voice to
+// play a new note. Find and free an existing voice. The channel
+// passed to the function is the channel for the new note to be
+// played.
+
+static opl_voice_t *ReplaceExistingVoice(opl_channel_data_t *channel)
+{
+ opl_voice_t *rover;
+ opl_voice_t *result;
+
+ // Check the allocated voices, if we find an instrument that is
+ // of a lower priority to the new instrument, discard it.
+ // If a voice is being used to play the second voice of an instrument,
+ // use that, as second voices are non-essential.
+ // Lower numbered MIDI channels implicitly have a higher priority
+ // than higher-numbered channels, eg. MIDI channel 1 is never
+ // discarded for MIDI channel 2.
+
+ result = NULL;
+
+ for (rover = voice_alloced_list; rover != NULL; rover = rover->next)
+ {
+ if (rover->current_instr_voice != 0
+ || (rover->channel > channel
+ && CompareChannelPriorities(channel, rover->channel) > 0))
+ {
+ result = rover;
+ break;
+ }
+ }
+
+ // If we didn't find a voice, find an existing voice being used to
+ // play a note on the same channel, and use that.
+
+ if (result == NULL)
+ {
+ for (rover = voice_alloced_list; rover != NULL; rover = rover->next)
+ {
+ if (rover->channel == channel)
+ {
+ result = rover;
+ break;
+ }
+ }
+ }
+
+ // Still nothing found? Give up and just use the first voice in
+ // the list.
+
+ if (result == NULL)
+ {
+ result = voice_alloced_list;
+ }
+
+ // Stop playing this voice playing and release it back to the free
+ // list.
+
+ VoiceKeyOff(result);
+ ReleaseVoice(result);
+
+ // Re-allocate the voice again and return it.
+
+ return GetFreeVoice();
+}
+
+
+static unsigned int FrequencyForVoice(opl_voice_t *voice)
+{
+ genmidi_voice_t *gm_voice;
+ unsigned int freq_index;
+ unsigned int octave;
+ unsigned int sub_index;
+ unsigned int note;
+
+ note = voice->note;
+
+ // Apply note offset.
+ // Don't apply offset if the instrument is a fixed note instrument.
+
+ gm_voice = &voice->current_instr->voices[voice->current_instr_voice];
+
+ if ((voice->current_instr->flags & GENMIDI_FLAG_FIXED) == 0)
+ {
+ note += (signed short) SHORT(gm_voice->base_note_offset);
+ }
+
+ // Avoid possible overflow due to base note offset:
+
+ if (note > 0x7f)
+ {
+ note = voice->note;
+ }
+
+ freq_index = 64 + 32 * note + voice->channel->bend;
+
+ // If this is the second voice of a double voice instrument, the
+ // frequency index can be adjusted by the fine tuning field.
+
+ if (voice->current_instr_voice != 0)
+ {
+ freq_index += (voice->current_instr->fine_tuning / 2) - 64;
+ }
+
+ // The first 7 notes use the start of the table, while
+ // consecutive notes loop around the latter part.
+
+ if (freq_index < 284)
+ {
+ return frequency_curve[freq_index];
+ }
+
+ sub_index = (freq_index - 284) % (12 * 32);
+ octave = (freq_index - 284) / (12 * 32);
+
+ // Once the seventh octave is reached, things break down.
+ // We can only go up to octave 7 as a maximum anyway (the OPL
+ // register only has three bits for octave number), but for the
+ // notes in octave 7, the first five bits have octave=7, the
+ // following notes have octave=6. This 7/6 pattern repeats in
+ // following octaves (which are technically impossible to
+ // represent anyway).
+
+ if (octave >= 7)
+ {
+ if (sub_index < 5)
+ {
+ octave = 7;
+ }
+ else
+ {
+ octave = 6;
+ }
+ }
+
+ // Calculate the resulting register value to use for the frequency.
+
+ return frequency_curve[sub_index + 284] | (octave << 10);
+}
+
+// Update the frequency that a voice is programmed to use.
+
+static void UpdateVoiceFrequency(opl_voice_t *voice)
+{
+ unsigned int freq;
+
+ // Calculate the frequency to use for this voice and update it
+ // if neccessary.
+
+ freq = FrequencyForVoice(voice);
+
+ if (voice->freq != freq)
+ {
+ OPL_WriteRegister(OPL_REGS_FREQ_1 + voice->index, freq & 0xff);
+ OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, (freq >> 8) | 0x20);
+
+ voice->freq = freq;
+ }
+}
+
+// Program a single voice for an instrument. For a double voice
+// instrument (GENMIDI_FLAG_2VOICE), this is called twice for each
+// key on event.
+
+static void VoiceKeyOn(opl_channel_data_t *channel,
+ genmidi_instr_t *instrument,
+ unsigned int instrument_voice,
+ unsigned int key,
+ unsigned int volume)
+{
+ opl_voice_t *voice;
+
+ // Find a voice to use for this new note.
+
+ voice = GetFreeVoice();
+
+ // If there are no more voices left, we must decide what to do.
+ // If this is the first voice of the instrument, free an existing
+ // voice and use that. Otherwise, if this is the second voice,
+ // it isn't as important; just discard it.
+
+ if (voice == NULL)
+ {
+ if (instrument_voice == 0)
+ {
+ voice = ReplaceExistingVoice(channel);
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ voice->channel = channel;
+ voice->key = key;
+
+ // Work out the note to use. This is normally the same as
+ // the key, unless it is a fixed pitch instrument.
+
+ if ((instrument->flags & GENMIDI_FLAG_FIXED) != 0)
+ {
+ voice->note = instrument->fixed_note;
+ }
+ else
+ {
+ voice->note = key;
+ }
+
+ // Program the voice with the instrument data:
+
+ SetVoiceInstrument(voice, instrument, instrument_voice);
+
+ // Set the volume level.
+
+ SetVoiceVolume(voice, volume);
+
+ // Write the frequency value to turn the note on.
+
+ voice->freq = 0;
+ UpdateVoiceFrequency(voice);
+}
+
+static void KeyOnEvent(opl_track_data_t *track, midi_event_t *event)
+{
+ genmidi_instr_t *instrument;
+ opl_channel_data_t *channel;
+ unsigned int key;
+ unsigned int volume;
+
+/*
+ printf("note on: channel %i, %i, %i\n",
+ event->data.channel.channel,
+ event->data.channel.param1,
+ event->data.channel.param2);
+*/
+
+ // The channel.
+
+ channel = &track->channels[event->data.channel.channel];
+ key = event->data.channel.param1;
+ volume = event->data.channel.param2;
+
+ // Percussion channel (10) is treated differently.
+
+ if (event->data.channel.channel == 9)
+ {
+ if (key < 35 || key > 81)
+ {
+ return;
+ }
+
+ instrument = &percussion_instrs[key - 35];
+ }
+ else
+ {
+ instrument = channel->instrument;
+ }
+
+ // Find and program a voice for this instrument. If this
+ // is a double voice instrument, we must do this twice.
+
+ VoiceKeyOn(channel, instrument, 0, key, volume);
+
+ if ((instrument->flags & GENMIDI_FLAG_2VOICE) != 0)
+ {
+ VoiceKeyOn(channel, instrument, 1, key, volume);
+ }
+}
+
+static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event)
+{
+ int channel;
+ int instrument;
+
+ // Set the instrument used on this channel.
+
+ channel = event->data.channel.channel;
+ instrument = event->data.channel.param1;
+ track->channels[channel].instrument = &main_instrs[instrument];
+
+ // TODO: Look through existing voices that are turned on on this
+ // channel, and change the instrument.
+}
+
+static void SetChannelVolume(opl_channel_data_t *channel, unsigned int volume)
+{
+ unsigned int i;
+
+ channel->volume = volume;
+
+ // Update all voices that this channel is using.
+
+ for (i=0; i<OPL_NUM_VOICES; ++i)
+ {
+ if (voices[i].channel == channel)
+ {
+ SetVoiceVolume(&voices[i], voices[i].note_volume);
+ }
+ }
+}
+
+static void ControllerEvent(opl_track_data_t *track, midi_event_t *event)
+{
+ unsigned int controller;
+ unsigned int param;
+ opl_channel_data_t *channel;
+
+/*
+ printf("change controller: channel %i, %i, %i\n",
+ event->data.channel.channel,
+ event->data.channel.param1,
+ event->data.channel.param2);
+*/
+
+ channel = &track->channels[event->data.channel.channel];
+ controller = event->data.channel.param1;
+ param = event->data.channel.param2;
+
+ switch (controller)
+ {
+ case MIDI_CONTROLLER_MAIN_VOLUME:
+ SetChannelVolume(channel, param);
+ break;
+
+ default:
+#ifdef OPL_MIDI_DEBUG
+ fprintf(stderr, "Unknown MIDI controller type: %i\n", controller);
+#endif
+ break;
+ }
+}
+
+// Process a pitch bend event.
+
+static void PitchBendEvent(opl_track_data_t *track, midi_event_t *event)
+{
+ opl_channel_data_t *channel;
+ unsigned int i;
+
+ // Update the channel bend value. Only the MSB of the pitch bend
+ // value is considered: this is what Doom does.
+
+ channel = &track->channels[event->data.channel.channel];
+ channel->bend = event->data.channel.param2 - 64;
+
+ // Update all voices for this channel.
+
+ for (i=0; i<OPL_NUM_VOICES; ++i)
+ {
+ if (voices[i].channel == channel)
+ {
+ UpdateVoiceFrequency(&voices[i]);
+ }
+ }
+}
+
+// Process a meta event.
+
+static void MetaEvent(opl_track_data_t *track, midi_event_t *event)
+{
+ switch (event->data.meta.type)
+ {
+ // Things we can just ignore.
+
+ case MIDI_META_SEQUENCE_NUMBER:
+ case MIDI_META_TEXT:
+ case MIDI_META_COPYRIGHT:
+ case MIDI_META_TRACK_NAME:
+ case MIDI_META_INSTR_NAME:
+ case MIDI_META_LYRICS:
+ case MIDI_META_MARKER:
+ case MIDI_META_CUE_POINT:
+ case MIDI_META_SEQUENCER_SPECIFIC:
+ break;
+
+ // End of track - actually handled when we run out of events
+ // in the track, see below.
+
+ case MIDI_META_END_OF_TRACK:
+ break;
+
+ default:
+#ifdef OPL_MIDI_DEBUG
+ fprintf(stderr, "Unknown MIDI meta event type: %i\n",
+ event->data.meta.type);
+#endif
+ break;
+ }
+}
+
+// Process a MIDI event from a track.
+
+static void ProcessEvent(opl_track_data_t *track, midi_event_t *event)
+{
+ switch (event->event_type)
+ {
+ case MIDI_EVENT_NOTE_OFF:
+ KeyOffEvent(track, event);
+ break;
+
+ case MIDI_EVENT_NOTE_ON:
+ KeyOnEvent(track, event);
+ break;
+
+ case MIDI_EVENT_CONTROLLER:
+ ControllerEvent(track, event);
+ break;
+
+ case MIDI_EVENT_PROGRAM_CHANGE:
+ ProgramChangeEvent(track, event);
+ break;
+
+ case MIDI_EVENT_PITCH_BEND:
+ PitchBendEvent(track, event);
+ break;
+
+ case MIDI_EVENT_META:
+ MetaEvent(track, event);
+ break;
+
+ // SysEx events can be ignored.
+
+ case MIDI_EVENT_SYSEX:
+ case MIDI_EVENT_SYSEX_SPLIT:
+ break;
+
+ default:
+#ifdef OPL_MIDI_DEBUG
+ fprintf(stderr, "Unknown MIDI event type %i\n", event->event_type);
+#endif
+ break;
+ }
+}
+
+static void ScheduleTrack(opl_track_data_t *track);
+
+// Restart a song from the beginning.
+
+static void RestartSong(void)
+{
+ unsigned int i;
+
+ running_tracks = num_tracks;
+
+ for (i=0; i<num_tracks; ++i)
+ {
+ MIDI_RestartIterator(tracks[i].iter);
+ ScheduleTrack(&tracks[i]);
+ }
+}
+
+// Callback function invoked when another event needs to be read from
+// a track.
+
+static void TrackTimerCallback(void *arg)
+{
+ opl_track_data_t *track = arg;
+ midi_event_t *event;
+
+ // Get the next event and process it.
+
+ if (!MIDI_GetNextEvent(track->iter, &event))
+ {
+ return;
+ }
+
+ ProcessEvent(track, event);
+
+ // End of track?
+
+ if (event->event_type == MIDI_EVENT_META
+ && event->data.meta.type == MIDI_META_END_OF_TRACK)
+ {
+ --running_tracks;
+
+ // When all tracks have finished, restart the song.
+
+ if (running_tracks <= 0 && song_looping)
+ {
+ RestartSong();
+ }
+
+ return;
+ }
+
+ // Reschedule the callback for the next event in the track.
+
+ ScheduleTrack(track);
+}
+
+static void ScheduleTrack(opl_track_data_t *track)
+{
+ unsigned int nticks;
+ unsigned int ms;
+ static int total = 0;
+
+ // Get the number of milliseconds until the next event.
+
+ nticks = MIDI_GetDeltaTime(track->iter);
+ ms = (nticks * track->ms_per_beat) / track->ticks_per_beat;
+ total += ms;
+
+ // Set a timer to be invoked when the next event is
+ // ready to play.
+
+ OPL_SetCallback(ms, TrackTimerCallback, track);
+}
+
+// Initialize a channel.
+
+static void InitChannel(opl_track_data_t *track, opl_channel_data_t *channel)
+{
+ // TODO: Work out sensible defaults?
+
+ channel->instrument = &main_instrs[0];
+ channel->volume = 127;
+ channel->bend = 0;
+}
+
+// Start a MIDI track playing:
+
+static void StartTrack(midi_file_t *file, unsigned int track_num)
+{
+ opl_track_data_t *track;
+ unsigned int i;
+
+ track = &tracks[track_num];
+ track->iter = MIDI_IterateTrack(file, track_num);
+ track->ticks_per_beat = MIDI_GetFileTimeDivision(file);
+
+ // Default is 120 bpm.
+ // TODO: this is wrong
+
+ track->ms_per_beat = 500 * 260;
+
+ for (i=0; i<MIDI_CHANNELS_PER_TRACK; ++i)
+ {
+ InitChannel(track, &track->channels[i]);
+ }
+
+ // Schedule the first event.
+
+ ScheduleTrack(track);
+}
+
+// Start playing a mid
+
+static void I_OPL_PlaySong(void *handle, boolean looping)
+{
+ midi_file_t *file;
+ unsigned int i;
+
+ if (!music_initialized || handle == NULL)
+ {
+ return;
+ }
+
+ file = handle;
+
+ // Allocate track data.
+
+ tracks = malloc(MIDI_NumTracks(file) * sizeof(opl_track_data_t));
+
+ num_tracks = MIDI_NumTracks(file);
+ running_tracks = num_tracks;
+ song_looping = looping;
+
+ for (i=0; i<num_tracks; ++i)
+ {
+ StartTrack(file, i);
+ }
+}
+
+static void I_OPL_PauseSong(void)
+{
+ unsigned int i;
+
+ if (!music_initialized)
+ {
+ return;
+ }
+
+ // Pause OPL callbacks.
+
+ OPL_SetPaused(1);
+
+ // Turn off all main instrument voices (not percussion).
+ // This is what Vanilla does.
+
+ for (i=0; i<OPL_NUM_VOICES; ++i)
+ {
+ if (voices[i].channel != NULL
+ && voices[i].current_instr < percussion_instrs)
+ {
+ VoiceKeyOff(&voices[i]);
+ }
+ }
+}
+
+static void I_OPL_ResumeSong(void)
+{
+ if (!music_initialized)
+ {
+ return;
+ }
+
+ OPL_SetPaused(0);
+}
+
+static void I_OPL_StopSong(void)
+{
+ unsigned int i;
+
+ if (!music_initialized)
+ {
+ return;
+ }
+
+ OPL_Lock();
+
+ // Stop all playback.
+
+ OPL_ClearCallbacks();
+
+ // Free all voices.
+
+ for (i=0; i<OPL_NUM_VOICES; ++i)
+ {
+ if (voices[i].channel != NULL)
+ {
+ VoiceKeyOff(&voices[i]);
+ ReleaseVoice(&voices[i]);
+ }
+ }
+
+ // Free all track data.
+
+ for (i=0; i<num_tracks; ++i)
+ {
+ MIDI_FreeIterator(tracks[i].iter);
+ }
+
+ free(tracks);
+
+ tracks = NULL;
+ num_tracks = 0;
+
+ OPL_Unlock();
+}
+
+static void I_OPL_UnRegisterSong(void *handle)
+{
+ if (!music_initialized)
+ {
+ return;
+ }
+
+ if (handle != NULL)
+ {
+ MIDI_FreeFile(handle);
+ }
+}
+
+// Determine whether memory block is a .mid file
+
+static boolean IsMid(byte *mem, int len)
+{
+ return len > 4 && !memcmp(mem, "MThd", 4);
+}
+
+static boolean ConvertMus(byte *musdata, int len, char *filename)
+{
+ MEMFILE *instream;
+ MEMFILE *outstream;
+ void *outbuf;
+ size_t outbuf_len;
+ int result;
+
+ instream = mem_fopen_read(musdata, len);
+ outstream = mem_fopen_write();
+
+ result = mus2mid(instream, outstream);
+
+ if (result == 0)
+ {
+ mem_get_buf(outstream, &outbuf, &outbuf_len);
+
+ M_WriteFile(filename, outbuf, outbuf_len);
+ }
+
+ mem_fclose(instream);
+ mem_fclose(outstream);
+
+ return result;
+}
+
+static void *I_OPL_RegisterSong(void *data, int len)
+{
+ midi_file_t *result;
+ char *filename;
+
+ if (!music_initialized)
+ {
+ return NULL;
+ }
+
+ // MUS files begin with "MUS"
+ // Reject anything which doesnt have this signature
+
+ filename = M_TempFile("doom.mid");
+
+ if (IsMid(data, len) && len < MAXMIDLENGTH)
+ {
+ M_WriteFile(filename, data, len);
+ }
+ else
+ {
+ // Assume a MUS file and try to convert
+
+ ConvertMus(data, len, filename);
+ }
+
+ result = MIDI_LoadFile(filename);
+
+ if (result == NULL)
+ {
+ fprintf(stderr, "I_OPL_RegisterSong: Failed to load MID.\n");
+ }
+
+ // remove file now
+
+ remove(filename);
+
+ Z_Free(filename);
+
+ return result;
+}
+
+// Is the song playing?
+
+static boolean I_OPL_MusicIsPlaying(void)
+{
+ if (!music_initialized)
+ {
+ return false;
+ }
+
+ return num_tracks > 0;
+}
+
+// Shutdown music
+
+static void I_OPL_ShutdownMusic(void)
+{
+ if (music_initialized)
+ {
+ // Stop currently-playing track, if there is one:
+
+ I_OPL_StopSong();
+
+ OPL_Shutdown();
+
+ // Release GENMIDI lump
+
+ W_ReleaseLumpName("GENMIDI");
+
+ music_initialized = false;
+ }
+}
+
+// Initialize music subsystem
+
+static boolean I_OPL_InitMusic(void)
+{
+ OPL_SetSampleRate(snd_samplerate);
+
+ if (!OPL_Init(opl_io_port))
+ {
+ printf("Dude. The Adlib isn't responding.\n");
+ return false;
+ }
+
+ // Load instruments from GENMIDI lump:
+
+ if (!LoadInstrumentTable())
+ {
+ OPL_Shutdown();
+ return false;
+ }
+
+ InitVoices();
+
+ tracks = NULL;
+ num_tracks = 0;
+ music_initialized = true;
+
+ return true;
+}
+
+static snddevice_t music_opl_devices[] =
+{
+ SNDDEVICE_ADLIB,
+ SNDDEVICE_SB,
+};
+
+music_module_t music_opl_module =
+{
+ music_opl_devices,
+ arrlen(music_opl_devices),
+ I_OPL_InitMusic,
+ I_OPL_ShutdownMusic,
+ I_OPL_SetMusicVolume,
+ I_OPL_PauseSong,
+ I_OPL_ResumeSong,
+ I_OPL_RegisterSong,
+ I_OPL_UnRegisterSong,
+ I_OPL_PlaySong,
+ I_OPL_StopSong,
+ I_OPL_MusicIsPlaying,
+};
+
diff --git a/src/i_scale.c b/src/i_scale.c
index 4f08f5d6..2c0b718c 100644
--- a/src/i_scale.c
+++ b/src/i_scale.c
@@ -56,11 +56,11 @@ static int dest_pitch;
// stretch_tables[1] : 40% / 60%
// All other combinations can be reached from these two tables.
-static byte *stretch_tables[2];
+static byte *stretch_tables[2] = { NULL, NULL };
// 50%/50% stretch table, for 800x600 squash mode
-static byte *half_stretch_table;
+static byte *half_stretch_table = NULL;
// Called to set the source and destination buffers before doing the
// scale.
@@ -367,6 +367,11 @@ static byte *GenerateStretchTable(byte *palette, int pct)
static void I_InitStretchTables(byte *palette)
{
+ if (stretch_tables[0] != NULL)
+ {
+ return;
+ }
+
// We only actually need two lookup tables:
//
// mix 0% = just write line 1
@@ -388,6 +393,11 @@ static void I_InitStretchTables(byte *palette)
static void I_InitSquashTable(byte *palette)
{
+ if (half_stretch_table != NULL)
+ {
+ return;
+ }
+
printf("I_InitSquashTable: Generating lookup table..");
fflush(stdout);
half_stretch_table = GenerateStretchTable(palette, 50);
diff --git a/src/i_sdlmusic.c b/src/i_sdlmusic.c
index 1e907739..0418e025 100644
--- a/src/i_sdlmusic.c
+++ b/src/i_sdlmusic.c
@@ -335,8 +335,6 @@ static boolean I_SDL_MusicIsPlaying(void)
static snddevice_t music_sdl_devices[] =
{
- SNDDEVICE_ADLIB,
- SNDDEVICE_SB,
SNDDEVICE_PAS,
SNDDEVICE_GUS,
SNDDEVICE_WAVEBLASTER,
diff --git a/src/i_sdlsound.c b/src/i_sdlsound.c
index 0b3f8aa3..7deb683d 100644
--- a/src/i_sdlsound.c
+++ b/src/i_sdlsound.c
@@ -25,7 +25,6 @@
//
//-----------------------------------------------------------------------------
-
#include "config.h"
#include <stdio.h>
@@ -42,6 +41,7 @@
#include "deh_str.h"
#include "i_sound.h"
#include "i_system.h"
+#include "i_swap.h"
#include "m_argv.h"
#include "w_wad.h"
#include "z_zone.h"
@@ -49,6 +49,7 @@
#include "doomtype.h"
#define LOW_PASS_FILTER
+//#define DEBUG_DUMP_WAVS
#define MAX_SOUND_SLICE_TIME 70 /* ms */
#define NUM_CHANNELS 16
@@ -288,6 +289,56 @@ static boolean ConvertibleRatio(int freq1, int freq2)
}
}
+#ifdef DEBUG_DUMP_WAVS
+
+// Debug code to dump resampled sound effects to WAV files for analysis.
+
+static void WriteWAV(char *filename, byte *data,
+ uint32_t length, int samplerate)
+{
+ FILE *wav;
+ unsigned int i;
+ unsigned short s;
+
+ wav = fopen(filename, "wb");
+
+ // Header
+
+ fwrite("RIFF", 1, 4, wav);
+ i = LONG(36 + samplerate);
+ fwrite(&i, 4, 1, wav);
+ fwrite("WAVE", 1, 4, wav);
+
+ // Subchunk 1
+
+ fwrite("fmt ", 1, 4, wav);
+ i = LONG(16);
+ fwrite(&i, 4, 1, wav); // Length
+ s = SHORT(1);
+ fwrite(&s, 2, 1, wav); // Format (PCM)
+ s = SHORT(2);
+ fwrite(&s, 2, 1, wav); // Channels (2=stereo)
+ i = LONG(samplerate);
+ fwrite(&i, 4, 1, wav); // Sample rate
+ i = LONG(samplerate * 2 * 2);
+ fwrite(&i, 4, 1, wav); // Byte rate (samplerate * stereo * 16 bit)
+ s = SHORT(2 * 2);
+ fwrite(&s, 2, 1, wav); // Block align (stereo * 16 bit)
+ s = SHORT(16);
+ fwrite(&s, 2, 1, wav); // Bits per sample (16 bit)
+
+ // Data subchunk
+
+ fwrite("data", 1, 4, wav);
+ i = LONG(length);
+ fwrite(&i, 4, 1, wav); // Data length
+ fwrite(data, 1, length, wav); // Data
+
+ fclose(wav);
+}
+
+#endif
+
// Generic sound expansion function for any sample rate.
// Returns number of clipped samples (always 0).
@@ -313,7 +364,7 @@ static void ExpandSoundData_SDL(sfxinfo_t *sfxinfo,
chunk = AllocateChunk(sfxinfo, expanded_length);
// If we can, use the standard / optimized SDL conversion routines.
-
+
if (samplerate <= mixer_freq
&& ConvertibleRatio(samplerate, mixer_freq)
&& SDL_BuildAudioCVT(&convertor,
@@ -379,9 +430,12 @@ static void ExpandSoundData_SDL(sfxinfo_t *sfxinfo,
rc = 1.0f / (3.14f * samplerate);
alpha = dt / (rc + dt);
- for (i=1; i<expanded_length; ++i)
+ // Both channels are processed in parallel, hence [i-2]:
+
+ for (i=2; i<expanded_length * 2; ++i)
{
- expanded[i] = (Sint16) (alpha * expanded[i] + (1 - alpha) * expanded[i-1]);
+ expanded[i] = (Sint16) (alpha * expanded[i]
+ + (1 - alpha) * expanded[i-2]);
}
}
#endif /* #ifdef LOW_PASS_FILTER */
@@ -432,6 +486,16 @@ static boolean CacheSFX(sfxinfo_t *sfxinfo)
ExpandSoundData(sfxinfo, data + 8, samplerate, length);
+#ifdef DEBUG_DUMP_WAVS
+ {
+ char filename[16];
+
+ sprintf(filename, "%s.wav", DEH_String(S_sfx[sound].name));
+ WriteWAV(filename, sound_chunks[sound].abuf,
+ sound_chunks[sound].alen, mixer_freq);
+ }
+#endif
+
// don't need the original lump any more
W_ReleaseLumpNum(lumpnum);
diff --git a/src/i_sound.c b/src/i_sound.c
index a9e953ce..0c771dc2 100644
--- a/src/i_sound.c
+++ b/src/i_sound.c
@@ -46,7 +46,7 @@ int snd_samplerate = 44100;
static sound_module_t *sound_module;
static music_module_t *music_module;
-int snd_musicdevice = SNDDEVICE_SB;
+int snd_musicdevice = SNDDEVICE_GENMIDI;
int snd_sfxdevice = SNDDEVICE_SB;
// Sound modules
@@ -54,6 +54,11 @@ int snd_sfxdevice = SNDDEVICE_SB;
extern sound_module_t sound_sdl_module;
extern sound_module_t sound_pcsound_module;
extern music_module_t music_sdl_module;
+extern music_module_t music_opl_module;
+
+// For OPL module:
+
+extern int opl_io_port;
// DOS-specific options: These are unused but should be maintained
// so that the config file can be shared between chocolate
@@ -81,6 +86,7 @@ static music_module_t *music_modules[] =
{
#ifdef FEATURE_SOUND
&music_sdl_module,
+ &music_opl_module,
#endif
NULL,
};
@@ -245,7 +251,6 @@ void I_UpdateSound(void)
static void CheckVolumeSeparation(int *sep, int *vol)
{
-return;
if (*sep < 0)
{
*sep = 0;
@@ -407,6 +412,7 @@ void I_BindSoundVariables(void)
M_BindVariable("snd_sbdma", &snd_sbdma);
M_BindVariable("snd_mport", &snd_mport);
M_BindVariable("snd_samplerate", &snd_samplerate);
+ M_BindVariable("opl_io_port", &opl_io_port);
#ifdef FEATURE_SOUND
M_BindVariable("use_libsamplerate", &use_libsamplerate);
#endif
diff --git a/src/i_video.c b/src/i_video.c
index a370fc08..733af899 100644
--- a/src/i_video.c
+++ b/src/i_video.c
@@ -144,8 +144,6 @@ static char *window_title = "";
static SDL_Color palette[256];
static boolean palette_to_set;
-static int windowwidth, windowheight;
-
// display has been set up?
static boolean initialized = false;
@@ -155,6 +153,10 @@ static boolean initialized = false;
static boolean nomouse = false;
int usemouse = 1;
+// Bit mask of mouse button state.
+
+static unsigned int mouse_button_state = 0;
+
// Disallow mouse and joystick movement to cause forward/backward
// motion. Specified with the '-novert' command line parameter.
// This is an int to allow saving to config file
@@ -235,6 +237,12 @@ static SDL_Cursor *cursors[2];
static screen_mode_t *screen_mode;
+// Window resize state.
+
+static boolean need_resize = false;
+static unsigned int resize_w, resize_h;
+static unsigned int last_resize_time;
+
// If true, keyboard mapping is ignored, like in Vanilla Doom.
// The sensible thing to do is to disable this if you have a non-US
// keyboard.
@@ -261,6 +269,8 @@ int mouse_threshold = 10;
int usegamma = 0;
+static void ApplyWindowResize(unsigned int w, unsigned int h);
+
static boolean MouseShouldBeGrabbed()
{
// never grab the mouse when in screensaver mode
@@ -524,29 +534,56 @@ void I_StartFrame (void)
}
-static int MouseButtonState(void)
+static void UpdateMouseButtonState(unsigned int button, boolean on)
{
- Uint8 state;
- int result = 0;
+ event_t event;
-#if SDL_VERSION_ATLEAST(1, 3, 0)
- state = SDL_GetMouseState(0, NULL, NULL);
-#else
- state = SDL_GetMouseState(NULL, NULL);
-#endif
+ if (button < SDL_BUTTON_LEFT || button > MAX_MOUSE_BUTTONS)
+ {
+ return;
+ }
// Note: button "0" is left, button "1" is right,
// button "2" is middle for Doom. This is different
// to how SDL sees things.
- if (state & SDL_BUTTON(1))
- result |= 1;
- if (state & SDL_BUTTON(3))
- result |= 2;
- if (state & SDL_BUTTON(2))
- result |= 4;
+ switch (button)
+ {
+ case SDL_BUTTON_LEFT:
+ button = 0;
+ break;
- return result;
+ case SDL_BUTTON_RIGHT:
+ button = 1;
+ break;
+
+ case SDL_BUTTON_MIDDLE:
+ button = 2;
+ break;
+
+ default:
+ // SDL buttons are indexed from 1.
+ --button;
+ break;
+ }
+
+ // Turn bit representing this button on or off.
+
+ if (on)
+ {
+ mouse_button_state |= (1 << button);
+ }
+ else
+ {
+ mouse_button_state &= ~(1 << button);
+ }
+
+ // Post an event with the new button state.
+
+ event.type = ev_mouse;
+ event.data1 = mouse_button_state;
+ event.data2 = event.data3 = 0;
+ D_PostEvent(&event);
}
static int AccelerateMouse(int val)
@@ -692,7 +729,7 @@ void I_GetEvent(void)
/*
case SDL_MOUSEMOTION:
event.type = ev_mouse;
- event.data1 = MouseButtonState();
+ event.data1 = mouse_button_state;
event.data2 = AccelerateMouse(sdlevent.motion.xrel);
event.data3 = -AccelerateMouse(sdlevent.motion.yrel);
D_PostEvent(&event);
@@ -702,20 +739,14 @@ void I_GetEvent(void)
case SDL_MOUSEBUTTONDOWN:
if (usemouse && !nomouse)
{
- event.type = ev_mouse;
- event.data1 = MouseButtonState();
- event.data2 = event.data3 = 0;
- D_PostEvent(&event);
+ UpdateMouseButtonState(sdlevent.button.button, true);
}
break;
case SDL_MOUSEBUTTONUP:
if (usemouse && !nomouse)
{
- event.type = ev_mouse;
- event.data1 = MouseButtonState();
- event.data2 = event.data3 = 0;
- D_PostEvent(&event);
+ UpdateMouseButtonState(sdlevent.button.button, false);
}
break;
@@ -733,6 +764,13 @@ void I_GetEvent(void)
palette_to_set = true;
break;
+ case SDL_RESIZABLE:
+ need_resize = true;
+ resize_w = sdlevent.resize.w;
+ resize_h = sdlevent.resize.h;
+ last_resize_time = SDL_GetTicks();
+ break;
+
default:
break;
}
@@ -777,7 +815,7 @@ static void I_ReadMouse(void)
if (x != 0 || y != 0)
{
ev.type = ev_mouse;
- ev.data1 = MouseButtonState();
+ ev.data1 = mouse_button_state;
ev.data2 = AccelerateMouse(x);
if (!novert)
@@ -976,14 +1014,20 @@ void I_FinishUpdate (void)
static int lasttic;
int tics;
int i;
- // UNUSED static unsigned char *bigscreen=0;
if (!initialized)
return;
if (noblit)
return;
-
+
+ if (need_resize && SDL_GetTicks() > last_resize_time + 500)
+ {
+ ApplyWindowResize(resize_w, resize_h);
+ need_resize = false;
+ palette_to_set = true;
+ }
+
UpdateGrab();
// Don't update the screen if the window isn't visible.
@@ -1692,11 +1736,96 @@ static char *WindowBoxType(screen_mode_t *mode, int w, int h)
}
}
+static void SetVideoMode(screen_mode_t *mode, int w, int h)
+{
+ byte *doompal;
+ int flags = 0;
+
+ doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE);
+
+ // Generate lookup tables before setting the video mode.
+
+ if (mode != NULL && mode->InitMode != NULL)
+ {
+ mode->InitMode(doompal);
+ }
+
+ // Set the video mode.
+
+ flags |= SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF;
+
+ if (fullscreen)
+ {
+ flags |= SDL_FULLSCREEN;
+ }
+ else
+ {
+ flags |= SDL_RESIZABLE;
+ }
+
+ screen = SDL_SetVideoMode(w, h, 8, flags);
+
+ if (screen == NULL)
+ {
+ I_Error("Error setting video mode: %s\n", SDL_GetError());
+ }
+
+ // If mode was not set, it must be set now that we know the
+ // screen size.
+
+ if (mode == NULL)
+ {
+ mode = I_FindScreenMode(screen->w, screen->h);
+
+ if (mode == NULL)
+ {
+ I_Error("I_InitGraphics: Unable to find a screen mode small "
+ "enough for %ix%i", screen->w, screen->h);
+ }
+
+ // Generate lookup tables before setting the video mode.
+
+ if (mode->InitMode != NULL)
+ {
+ mode->InitMode(doompal);
+ }
+ }
+
+ // Save screen mode.
+
+ screen_mode = mode;
+}
+
+static void ApplyWindowResize(unsigned int w, unsigned int h)
+{
+ screen_mode_t *mode;
+
+ // Find the biggest screen mode that will fall within these
+ // dimensions, falling back to the smallest mode possible if
+ // none is found.
+
+ mode = I_FindScreenMode(w, h);
+
+ if (mode == NULL)
+ {
+ mode = I_FindScreenMode(SCREENWIDTH, SCREENHEIGHT);
+ }
+
+ // Reset mode to resize window.
+
+ printf("Resize to %ix%i\n", mode->width, mode->height);
+ SetVideoMode(mode, mode->width, mode->height);
+
+ // Save settings.
+
+ screen_width = mode->width;
+ screen_height = mode->height;
+}
+
void I_InitGraphics(void)
{
SDL_Event dummy;
byte *doompal;
- int flags = 0;
char *env;
// Pass through the XSCREENSAVER_WINDOW environment variable to
@@ -1727,70 +1856,53 @@ void I_InitGraphics(void)
CheckCommandLine();
- doompal = W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE);
+ // Set up title and icon. Windows cares about the ordering; this
+ // has to be done before the call to SDL_SetVideoMode.
+
+ I_InitWindowTitle();
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
+ I_InitWindowIcon();
+#endif
+
+ //
+ // Enter into graphics mode.
+ //
+ // When in screensaver mode, run full screen and auto detect
+ // screen dimensions (don't change video mode)
+ //
if (screensaver_mode)
{
- windowwidth = 0;
- windowheight = 0;
+ SetVideoMode(NULL, 0, 0);
}
else
{
+ int w, h;
+
if (autoadjust_video_settings)
{
I_AutoAdjustSettings();
}
- windowwidth = screen_width;
- windowheight = screen_height;
+ w = screen_width;
+ h = screen_height;
- screen_mode = I_FindScreenMode(windowwidth, windowheight);
+ screen_mode = I_FindScreenMode(w, h);
if (screen_mode == NULL)
{
I_Error("I_InitGraphics: Unable to find a screen mode small "
- "enough for %ix%i", windowwidth, windowheight);
+ "enough for %ix%i", w, h);
}
- if (windowwidth != screen_mode->width
- || windowheight != screen_mode->height)
+ if (w != screen_mode->width || h != screen_mode->height)
{
printf("I_InitGraphics: %s (%ix%i within %ix%i)\n",
- WindowBoxType(screen_mode, windowwidth, windowheight),
- screen_mode->width, screen_mode->height,
- windowwidth, windowheight);
+ WindowBoxType(screen_mode, w, h),
+ screen_mode->width, screen_mode->height, w, h);
}
- // Generate lookup tables before setting the video mode.
-
- if (screen_mode->InitMode != NULL)
- {
- screen_mode->InitMode(doompal);
- }
- }
-
- // Set up title and icon. Windows cares about the ordering; this
- // has to be done before the call to SDL_SetVideoMode.
-
- I_InitWindowTitle();
-#if !SDL_VERSION_ATLEAST(1, 3, 0)
- I_InitWindowIcon();
-#endif
-
- // Set the video mode.
-
- flags |= SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF;
-
- if (fullscreen)
- {
- flags |= SDL_FULLSCREEN;
- }
-
- screen = SDL_SetVideoMode(windowwidth, windowheight, 8, flags);
-
- if (screen == NULL)
- {
- I_Error("Error setting video mode: %s\n", SDL_GetError());
+ SetVideoMode(screen_mode, w, h);
}
// Start with a clear black screen
@@ -1811,6 +1923,7 @@ void I_InitGraphics(void)
// Set the palette
+ doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE);
I_SetPalette(doompal);
SDL_SetColors(screen, palette, 0, 256);
@@ -1819,26 +1932,6 @@ void I_InitGraphics(void)
UpdateFocus();
UpdateGrab();
- // In screensaver mode, now find a screen_mode to use.
-
- if (screensaver_mode)
- {
- screen_mode = I_FindScreenMode(screen->w, screen->h);
-
- if (screen_mode == NULL)
- {
- I_Error("I_InitGraphics: Unable to find a screen mode small "
- "enough for %ix%i", screen->w, screen->h);
- }
-
- // Generate lookup tables before setting the video mode.
-
- if (screen_mode->InitMode != NULL)
- {
- screen_mode->InitMode(doompal);
- }
- }
-
// On some systems, it takes a second or so for the screen to settle
// after changing modes. We include the option to add a delay when
// setting the screen mode, so that the game doesn't start immediately
@@ -1854,12 +1947,12 @@ void I_InitGraphics(void)
// Likewise if the screen pitch is not the same as the width
// If we have to multiply, drawing is done to a separate 320x200 buf
- native_surface = !SDL_MUSTLOCK(screen)
+ native_surface = !SDL_MUSTLOCK(screen)
&& screen_mode == &mode_scale_1x
&& screen->pitch == SCREENWIDTH
&& aspect_ratio_correct;
- // If not, allocate a buffer and copy from that buffer to the
+ // If not, allocate a buffer and copy from that buffer to the
// screen when we do an update
if (native_surface)
diff --git a/src/i_video.h b/src/i_video.h
index af865287..82368967 100644
--- a/src/i_video.h
+++ b/src/i_video.h
@@ -43,7 +43,9 @@
#define SCREENHEIGHT_4_3 240
-typedef struct
+#define MAX_MOUSE_BUTTONS 8
+
+typedef struct
{
// Screen width and height
diff --git a/src/m_argv.c b/src/m_argv.c
index e2b551f1..79702e56 100644
--- a/src/m_argv.c
+++ b/src/m_argv.c
@@ -101,7 +101,7 @@ static void LoadResponseFile(int argv_index)
size = M_FileLength(handle);
// Read in the entire file
- // Allocate one byte extra - this is incase there is an argument
+ // Allocate one byte extra - this is in case there is an argument
// at the end of the response file, in which case a '\0' will be
// needed.
diff --git a/src/m_config.c b/src/m_config.c
index f3e6e913..d3085b05 100644
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -60,6 +60,7 @@ static char *default_extra_config;
typedef enum
{
DEFAULT_INT,
+ DEFAULT_INT_HEX,
DEFAULT_STRING,
DEFAULT_FLOAT,
DEFAULT_KEY,
@@ -99,14 +100,19 @@ typedef struct
char *filename;
} default_collection_t;
+#define CONFIG_VARIABLE_GENERIC(name, type) \
+ { #name, NULL, type, 0, 0, false }
+
#define CONFIG_VARIABLE_KEY(name) \
- { #name, NULL, DEFAULT_KEY, 0, 0, false }
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_KEY)
#define CONFIG_VARIABLE_INT(name) \
- { #name, NULL, DEFAULT_INT, 0, 0, false }
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_INT)
+#define CONFIG_VARIABLE_INT_HEX(name) \
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_INT_HEX)
#define CONFIG_VARIABLE_FLOAT(name) \
- { #name, NULL, DEFAULT_FLOAT, 0, 0, false }
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_FLOAT)
#define CONFIG_VARIABLE_STRING(name) \
- { #name, NULL, DEFAULT_STRING, 0, 0, false }
+ CONFIG_VARIABLE_GENERIC(name, DEFAULT_STRING)
//! @begin_config_file default.cfg
@@ -664,20 +670,27 @@ static default_t extra_defaults_list[] =
//!
// Mouse acceleration threshold. When the speed of mouse movement
- // exceeds this threshold value, the speed is multiplied by an
+ // exceeds this threshold value, the speed is multiplied by an
// acceleration factor (mouse_acceleration).
//
CONFIG_VARIABLE_INT(mouse_threshold),
//!
- // Sound output sample rate, in Hz. Typical values to use are
+ // Sound output sample rate, in Hz. Typical values to use are
// 11025, 22050, 44100 and 48000.
//
CONFIG_VARIABLE_INT(snd_samplerate),
//!
+ // The I/O port to use to access the OPL chip. Only relevant when
+ // using native OPL music playback.
+ //
+
+ CONFIG_VARIABLE_INT_HEX(opl_io_port),
+
+ //!
// If non-zero, the ENDOOM screen is displayed when exiting the
// game. If zero, the ENDOOM screen is not displayed.
//
@@ -772,6 +785,18 @@ static default_t extra_defaults_list[] =
CONFIG_VARIABLE_INT(joyb_straferight),
//!
+ // Joystick button to cycle to the previous weapon.
+ //
+
+ CONFIG_VARIABLE_INT(joyb_prevweapon),
+
+ //!
+ // Joystick button to cycle to the next weapon.
+ //
+
+ CONFIG_VARIABLE_INT(joyb_nextweapon),
+
+ //!
// Mouse button to strafe left.
//
@@ -796,6 +821,18 @@ static default_t extra_defaults_list[] =
CONFIG_VARIABLE_INT(mouseb_backward),
//!
+ // Mouse button to cycle to the previous weapon.
+ //
+
+ CONFIG_VARIABLE_INT(mouseb_prevweapon),
+
+ //!
+ // Mouse button to cycle to the next weapon.
+ //
+
+ CONFIG_VARIABLE_INT(mouseb_nextweapon),
+
+ //!
// If non-zero, double-clicking a mouse button acts like pressing
// the "use" key to use an object in-game, eg. a door or switch.
//
@@ -948,6 +985,12 @@ static default_t extra_defaults_list[] =
CONFIG_VARIABLE_KEY(key_menu_gamma),
//!
+ // Keyboard shortcut to switch view in multiplayer.
+ //
+
+ CONFIG_VARIABLE_KEY(key_spy),
+
+ //!
// Keyboard shortcut to increase the screen size.
//
@@ -1080,10 +1123,82 @@ static default_t extra_defaults_list[] =
CONFIG_VARIABLE_KEY(key_weapon8),
//!
+ // Key to cycle to the previous weapon.
+ //
+
+ CONFIG_VARIABLE_KEY(key_prevweapon),
+
+ //!
+ // Key to cycle to the next weapon.
+ //
+
+ CONFIG_VARIABLE_KEY(key_nextweapon),
+
+ //!
// Key to re-display last message.
//
CONFIG_VARIABLE_KEY(key_message_refresh),
+
+ //!
+ // Key to quit the game when recording a demo.
+ //
+
+ CONFIG_VARIABLE_KEY(key_demo_quit),
+
+ //!
+ // Key to send a message during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msg),
+
+ //!
+ // Key to send a message to player 1 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer1),
+
+ //!
+ // Key to send a message to player 2 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer2),
+
+ //!
+ // Key to send a message to player 3 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer3),
+
+ //!
+ // Key to send a message to player 4 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer4),
+
+ //!
+ // Key to send a message to player 5 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer5),
+
+ //!
+ // Key to send a message to player 6 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer6),
+
+ //!
+ // Key to send a message to player 7 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer7),
+
+ //!
+ // Key to send a message to player 8 during multiplayer games.
+ //
+
+ CONFIG_VARIABLE_KEY(key_multi_msgplayer8)
};
static default_collection_t extra_defaults =
@@ -1205,6 +1320,10 @@ static void SaveDefaultCollection(default_collection_t *collection)
fprintf(f, "%i", * (int *) defaults[i].location);
break;
+ case DEFAULT_INT_HEX:
+ fprintf(f, "0x%x", * (int *) defaults[i].location);
+ break;
+
case DEFAULT_FLOAT:
fprintf(f, "%f", * (float *) defaults[i].location);
break;
@@ -1294,6 +1413,7 @@ static void LoadDefaultCollection(default_collection_t *collection)
break;
case DEFAULT_INT:
+ case DEFAULT_INT_HEX:
* (int *) def->location = ParseIntParameter(strparm);
break;
diff --git a/src/m_controls.c b/src/m_controls.c
index 0f64249d..8b8af160 100644
--- a/src/m_controls.c
+++ b/src/m_controls.c
@@ -22,6 +22,8 @@
//
//-----------------------------------------------------------------------------
+#include <stdio.h>
+
#include "doomtype.h"
#include "doomkeys.h"
@@ -100,8 +102,19 @@ int mousebstraferight = -1;
int mousebbackward = -1;
int mousebuse = -1;
+int mousebprevweapon = -1;
+int mousebnextweapon = -1;
+
+
int key_message_refresh = KEY_ENTER;
int key_pause = KEY_PAUSE;
+int key_demo_quit = 'q';
+int key_spy = KEY_F12;
+
+// Multiplayer chat keys:
+
+int key_multi_msg = 't';
+int key_multi_msgplayer[8];
// Weapon selection keys:
@@ -113,8 +126,10 @@ int key_weapon5 = '5';
int key_weapon6 = '6';
int key_weapon7 = '7';
int key_weapon8 = '8';
+int key_prevweapon = 0;
+int key_nextweapon = 0;
-// Map controls keys:
+// Map control keys:
int key_map_north = KEY_UPARROW;
int key_map_south = KEY_DOWNARROW;
@@ -170,6 +185,9 @@ int joybstraferight = -1;
int joybjump = -1;
+int joybprevweapon = -1;
+int joybnextweapon = -1;
+
// Control whether if a mouse button is double clicked, it acts like
// "use" has been pressed
@@ -202,7 +220,7 @@ void M_BindBaseControls(void)
M_BindVariable("joyb_speed", &joybspeed),
// Extra controls that are not in the Vanilla versions:
-
+
M_BindVariable("joyb_strafeleft", &joybstrafeleft);
M_BindVariable("joyb_straferight", &joybstraferight);
M_BindVariable("mouseb_strafeleft", &mousebstrafeleft);
@@ -278,6 +296,15 @@ void M_BindWeaponControls(void)
M_BindVariable("key_weapon6", &key_weapon6);
M_BindVariable("key_weapon7", &key_weapon7);
M_BindVariable("key_weapon8", &key_weapon8);
+
+ M_BindVariable("key_prevweapon", &key_prevweapon);
+ M_BindVariable("key_nextweapon", &key_nextweapon);
+
+ M_BindVariable("joyb_prevweapon", &joybprevweapon);
+ M_BindVariable("joyb_nextweapon", &joybnextweapon);
+
+ M_BindVariable("mouseb_prevweapon", &mousebprevweapon);
+ M_BindVariable("mouseb_nextweapon", &mousebnextweapon);
}
void M_BindMapControls(void)
@@ -322,6 +349,22 @@ void M_BindMenuControls(void)
M_BindVariable("key_menu_incscreen", &key_menu_incscreen);
M_BindVariable("key_menu_decscreen", &key_menu_decscreen);
+ M_BindVariable("key_demo_quit", &key_demo_quit);
+ M_BindVariable("key_spy", &key_spy);
+}
+
+void M_BindChatControls(unsigned int num_players)
+{
+ char name[20];
+ int i;
+
+ M_BindVariable("key_multi_msg", &key_multi_msg);
+
+ for (i=0; i<num_players; ++i)
+ {
+ sprintf(name, "key_multi_msgplayer%i", i + 1);
+ M_BindVariable(name, &key_multi_msgplayer[i]);
+ }
}
#ifdef _WIN32_WCE
diff --git a/src/m_controls.h b/src/m_controls.h
index 10ca7a0c..3e50d557 100644
--- a/src/m_controls.h
+++ b/src/m_controls.h
@@ -63,6 +63,9 @@ extern int key_invdrop;
extern int key_message_refresh;
extern int key_pause;
+extern int key_multi_msg;
+extern int key_multi_msgplayer[8];
+
extern int key_weapon1;
extern int key_weapon2;
extern int key_weapon3;
@@ -72,6 +75,11 @@ extern int key_weapon6;
extern int key_weapon7;
extern int key_weapon8;
+extern int key_demo_quit;
+extern int key_spy;
+extern int key_prevweapon;
+extern int key_nextweapon;
+
extern int key_map_north;
extern int key_map_south;
extern int key_map_east;
@@ -136,6 +144,9 @@ extern int mousebstraferight;
extern int mousebbackward;
extern int mousebuse;
+extern int mousebprevweapon;
+extern int mousebnextweapon;
+
extern int joybfire;
extern int joybstrafe;
extern int joybuse;
@@ -146,8 +157,11 @@ extern int joybjump;
extern int joybstrafeleft;
extern int joybstraferight;
+extern int joybprevweapon;
+extern int joybnextweapon;
+
extern int dclick_use;
-
+
void M_BindBaseControls(void);
void M_BindHereticControls(void);
void M_BindHexenControls(void);
@@ -155,6 +169,7 @@ void M_BindStrifeControls(void);
void M_BindWeaponControls(void);
void M_BindMapControls(void);
void M_BindMenuControls(void);
+void M_BindChatControls(unsigned int num_players);
void M_ApplyPlatformDefaults(void);
diff --git a/src/m_misc.c b/src/m_misc.c
index 5847f1a2..ed41b5f1 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -255,3 +255,37 @@ void M_ForceUppercase(char *text)
}
}
+//
+// M_StrCaseStr
+//
+// Case-insensitive version of strstr()
+//
+
+char *M_StrCaseStr(char *haystack, char *needle)
+{
+ unsigned int haystack_len;
+ unsigned int needle_len;
+ unsigned int len;
+ unsigned int i;
+
+ haystack_len = strlen(haystack);
+ needle_len = strlen(needle);
+
+ if (haystack_len < needle_len)
+ {
+ return NULL;
+ }
+
+ len = haystack_len - needle_len;
+
+ for (i = 0; i <= len; ++i)
+ {
+ if (!strncasecmp(haystack + i, needle, needle_len))
+ {
+ return haystack + i;
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/src/m_misc.h b/src/m_misc.h
index c92ddde8..c6be6ccb 100644
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -42,7 +42,7 @@ long M_FileLength(FILE *handle);
boolean M_StrToInt(const char *str, int *result);
void M_ExtractFileBase(char *path, char *dest);
void M_ForceUppercase(char *text);
-
+char *M_StrCaseStr(char *haystack, char *needle);
#endif
diff --git a/src/midifile.c b/src/midifile.c
new file mode 100644
index 00000000..1990dcdc
--- /dev/null
+++ b/src/midifile.c
@@ -0,0 +1,814 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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:
+// Reading of MIDI files.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "doomtype.h"
+#include "i_swap.h"
+#include "midifile.h"
+
+#define HEADER_CHUNK_ID "MThd"
+#define TRACK_CHUNK_ID "MTrk"
+#define MAX_BUFFER_SIZE 0x10000
+
+typedef struct
+{
+ byte chunk_id[4];
+ unsigned int chunk_size;
+} PACKEDATTR chunk_header_t;
+
+typedef struct
+{
+ chunk_header_t chunk_header;
+ unsigned short format_type;
+ unsigned short num_tracks;
+ unsigned short time_division;
+} PACKEDATTR midi_header_t;
+
+typedef struct
+{
+ // Length in bytes:
+
+ unsigned int data_len;
+
+ // Events in this track:
+
+ midi_event_t *events;
+ int num_events;
+} midi_track_t;
+
+struct midi_track_iter_s
+{
+ midi_track_t *track;
+ unsigned int position;
+};
+
+struct midi_file_s
+{
+ midi_header_t header;
+
+ // All tracks in this file:
+ midi_track_t *tracks;
+ unsigned int num_tracks;
+
+ // Data buffer used to store data read for SysEx or meta events:
+ byte *buffer;
+ unsigned int buffer_size;
+};
+
+// Check the header of a chunk:
+
+static boolean CheckChunkHeader(chunk_header_t *chunk,
+ char *expected_id)
+{
+ boolean result;
+
+ result = (memcmp((char *) chunk->chunk_id, expected_id, 4) == 0);
+
+ if (!result)
+ {
+ fprintf(stderr, "CheckChunkHeader: Expected '%s' chunk header, "
+ "got '%c%c%c%c'\n",
+ expected_id,
+ chunk->chunk_id[0], chunk->chunk_id[1],
+ chunk->chunk_id[2], chunk->chunk_id[3]);
+ }
+
+ return result;
+}
+
+// Read a single byte. Returns false on error.
+
+static boolean ReadByte(byte *result, FILE *stream)
+{
+ int c;
+
+ c = fgetc(stream);
+
+ if (c == EOF)
+ {
+ fprintf(stderr, "ReadByte: Unexpected end of file\n");
+ return false;
+ }
+ else
+ {
+ *result = (byte) c;
+
+ return true;
+ }
+}
+
+// Read a variable-length value.
+
+static boolean ReadVariableLength(unsigned int *result, FILE *stream)
+{
+ int i;
+ byte b;
+
+ *result = 0;
+
+ for (i=0; i<4; ++i)
+ {
+ if (!ReadByte(&b, stream))
+ {
+ fprintf(stderr, "ReadVariableLength: Error while reading "
+ "variable-length value\n");
+ return false;
+ }
+
+ // Insert the bottom seven bits from this byte.
+
+ *result <<= 7;
+ *result |= b & 0x7f;
+
+ // If the top bit is not set, this is the end.
+
+ if ((b & 0x80) == 0)
+ {
+ return true;
+ }
+ }
+
+ fprintf(stderr, "ReadVariableLength: Variable-length value too "
+ "long: maximum of four bytes\n");
+ return false;
+}
+
+// Read a byte sequence into the data buffer.
+
+static void *ReadByteSequence(unsigned int num_bytes, FILE *stream)
+{
+ unsigned int i;
+ byte *result;
+
+ // Allocate a buffer:
+
+ result = malloc(num_bytes);
+
+ if (result == NULL)
+ {
+ fprintf(stderr, "ReadByteSequence: Failed to allocate buffer\n");
+ return NULL;
+ }
+
+ // Read the data:
+
+ for (i=0; i<num_bytes; ++i)
+ {
+ if (!ReadByte(&result[i], stream))
+ {
+ fprintf(stderr, "ReadByteSequence: Error while reading byte %u\n",
+ i);
+ free(result);
+ return NULL;
+ }
+ }
+
+ return result;
+}
+
+// Read a MIDI channel event.
+// two_param indicates that the event type takes two parameters
+// (three byte) otherwise it is single parameter (two byte)
+
+static boolean ReadChannelEvent(midi_event_t *event,
+ byte event_type, boolean two_param,
+ FILE *stream)
+{
+ byte b;
+
+ // Set basics:
+
+ event->event_type = event_type & 0xf0;
+ event->data.channel.channel = event_type & 0x0f;
+
+ // Read parameters:
+
+ if (!ReadByte(&b, stream))
+ {
+ fprintf(stderr, "ReadChannelEvent: Error while reading channel "
+ "event parameters\n");
+ return false;
+ }
+
+ event->data.channel.param1 = b;
+
+ // Second parameter:
+
+ if (two_param)
+ {
+ if (!ReadByte(&b, stream))
+ {
+ fprintf(stderr, "ReadChannelEvent: Error while reading channel "
+ "event parameters\n");
+ return false;
+ }
+
+ event->data.channel.param2 = b;
+ }
+
+ return true;
+}
+
+// Read sysex event:
+
+static boolean ReadSysExEvent(midi_event_t *event, int event_type,
+ FILE *stream)
+{
+ event->event_type = event_type;
+
+ if (!ReadVariableLength(&event->data.sysex.length, stream))
+ {
+ fprintf(stderr, "ReadSysExEvent: Failed to read length of "
+ "SysEx block\n");
+ return false;
+ }
+
+ // Read the byte sequence:
+
+ event->data.sysex.data = ReadByteSequence(event->data.sysex.length, stream);
+
+ if (event->data.sysex.data == NULL)
+ {
+ fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n");
+ return false;
+ }
+
+ return true;
+}
+
+// Read meta event:
+
+static boolean ReadMetaEvent(midi_event_t *event, FILE *stream)
+{
+ byte b;
+
+ event->event_type = MIDI_EVENT_META;
+
+ // Read meta event type:
+
+ if (!ReadByte(&b, stream))
+ {
+ fprintf(stderr, "ReadMetaEvent: Failed to read meta event type\n");
+ return false;
+ }
+
+ event->data.meta.type = b;
+
+ // Read length of meta event data:
+
+ if (!ReadVariableLength(&event->data.meta.length, stream))
+ {
+ fprintf(stderr, "ReadSysExEvent: Failed to read length of "
+ "SysEx block\n");
+ return false;
+ }
+
+ // Read the byte sequence:
+
+ event->data.meta.data = ReadByteSequence(event->data.meta.length, stream);
+
+ if (event->data.meta.data == NULL)
+ {
+ fprintf(stderr, "ReadSysExEvent: Failed while reading SysEx event\n");
+ return false;
+ }
+
+ return true;
+}
+
+static boolean ReadEvent(midi_event_t *event, unsigned int *last_event_type,
+ FILE *stream)
+{
+ byte event_type;
+
+ if (!ReadVariableLength(&event->delta_time, stream))
+ {
+ fprintf(stderr, "ReadEvent: Failed to read event timestamp\n");
+ return false;
+ }
+
+ if (!ReadByte(&event_type, stream))
+ {
+ fprintf(stderr, "ReadEvent: Failed to read event type\n");
+ return false;
+ }
+
+ // All event types have their top bit set. Therefore, if
+ // the top bit is not set, it is because we are using the "same
+ // as previous event type" shortcut to save a byte. Skip back
+ // a byte so that we read this byte again.
+
+ if ((event_type & 0x80) == 0)
+ {
+ event_type = *last_event_type;
+
+ if (fseek(stream, -1, SEEK_CUR) < 0)
+ {
+ fprintf(stderr, "ReadEvent: Unable to seek in stream\n");
+ return false;
+ }
+ }
+ else
+ {
+ *last_event_type = event_type;
+ }
+
+ // Check event type:
+
+ switch (event_type & 0xf0)
+ {
+ // Two parameter channel events:
+
+ case MIDI_EVENT_NOTE_OFF:
+ case MIDI_EVENT_NOTE_ON:
+ case MIDI_EVENT_AFTERTOUCH:
+ case MIDI_EVENT_CONTROLLER:
+ case MIDI_EVENT_PITCH_BEND:
+ return ReadChannelEvent(event, event_type, true, stream);
+
+ // Single parameter channel events:
+
+ case MIDI_EVENT_PROGRAM_CHANGE:
+ case MIDI_EVENT_CHAN_AFTERTOUCH:
+ return ReadChannelEvent(event, event_type, false, stream);
+
+ default:
+ break;
+ }
+
+ // Specific value?
+
+ switch (event_type)
+ {
+ case MIDI_EVENT_SYSEX:
+ case MIDI_EVENT_SYSEX_SPLIT:
+ return ReadSysExEvent(event, event_type, stream);
+
+ case MIDI_EVENT_META:
+ return ReadMetaEvent(event, stream);
+
+ default:
+ break;
+ }
+
+ fprintf(stderr, "ReadEvent: Unknown MIDI event type: 0x%x\n", event_type);
+ return false;
+}
+
+// Free an event:
+
+static void FreeEvent(midi_event_t *event)
+{
+ // Some event types have dynamically allocated buffers assigned
+ // to them that must be freed.
+
+ switch (event->event_type)
+ {
+ case MIDI_EVENT_SYSEX:
+ case MIDI_EVENT_SYSEX_SPLIT:
+ free(event->data.sysex.data);
+ break;
+
+ case MIDI_EVENT_META:
+ free(event->data.meta.data);
+ break;
+
+ default:
+ // Nothing to do.
+ break;
+ }
+}
+
+// Read and check the track chunk header
+
+static boolean ReadTrackHeader(midi_track_t *track, FILE *stream)
+{
+ size_t records_read;
+ chunk_header_t chunk_header;
+
+ records_read = fread(&chunk_header, sizeof(chunk_header_t), 1, stream);
+
+ if (records_read < 1)
+ {
+ return false;
+ }
+
+ if (!CheckChunkHeader(&chunk_header, TRACK_CHUNK_ID))
+ {
+ return false;
+ }
+
+ track->data_len = SDL_SwapBE32(chunk_header.chunk_size);
+
+ return true;
+}
+
+static boolean ReadTrack(midi_track_t *track, FILE *stream)
+{
+ midi_event_t *new_events;
+ midi_event_t *event;
+ unsigned int last_event_type;
+
+ track->num_events = 0;
+ track->events = NULL;
+
+ // Read the header:
+
+ if (!ReadTrackHeader(track, stream))
+ {
+ return false;
+ }
+
+ // Then the events:
+
+ last_event_type = 0;
+
+ for (;;)
+ {
+ // Resize the track slightly larger to hold another event:
+
+ new_events = realloc(track->events,
+ sizeof(midi_event_t) * (track->num_events + 1));
+
+ if (new_events == NULL)
+ {
+ return false;
+ }
+
+ track->events = new_events;
+
+ // Read the next event:
+
+ event = &track->events[track->num_events];
+ if (!ReadEvent(event, &last_event_type, stream))
+ {
+ return false;
+ }
+
+ ++track->num_events;
+
+ // End of track?
+
+ if (event->event_type == MIDI_EVENT_META
+ && event->data.meta.type == MIDI_META_END_OF_TRACK)
+ {
+ break;
+ }
+ }
+
+ return true;
+}
+
+// Free a track:
+
+static void FreeTrack(midi_track_t *track)
+{
+ unsigned int i;
+
+ for (i=0; i<track->num_events; ++i)
+ {
+ FreeEvent(&track->events[i]);
+ }
+
+ free(track->events);
+}
+
+static boolean ReadAllTracks(midi_file_t *file, FILE *stream)
+{
+ unsigned int i;
+
+ // Allocate list of tracks and read each track:
+
+ file->tracks = malloc(sizeof(midi_track_t) * file->num_tracks);
+
+ if (file->tracks == NULL)
+ {
+ return false;
+ }
+
+ memset(file->tracks, 0, sizeof(midi_track_t) * file->num_tracks);
+
+ // Read each track:
+
+ for (i=0; i<file->num_tracks; ++i)
+ {
+ if (!ReadTrack(&file->tracks[i], stream))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Read and check the header chunk.
+
+static boolean ReadFileHeader(midi_file_t *file, FILE *stream)
+{
+ size_t records_read;
+ unsigned int format_type;
+
+ records_read = fread(&file->header, sizeof(midi_header_t), 1, stream);
+
+ if (records_read < 1)
+ {
+ return false;
+ }
+
+ if (!CheckChunkHeader(&file->header.chunk_header, HEADER_CHUNK_ID)
+ || SDL_SwapBE32(file->header.chunk_header.chunk_size) != 6)
+ {
+ fprintf(stderr, "ReadFileHeader: Invalid MIDI chunk header! "
+ "chunk_size=%i\n",
+ SDL_SwapBE32(file->header.chunk_header.chunk_size));
+ return false;
+ }
+
+ format_type = SDL_SwapBE16(file->header.format_type);
+ file->num_tracks = SDL_SwapBE16(file->header.num_tracks);
+
+ if ((format_type != 0 && format_type != 1)
+ || file->num_tracks < 1)
+ {
+ fprintf(stderr, "ReadFileHeader: Only type 0/1 "
+ "MIDI files supported!\n");
+ return false;
+ }
+
+ return true;
+}
+
+void MIDI_FreeFile(midi_file_t *file)
+{
+ int i;
+
+ if (file->tracks != NULL)
+ {
+ for (i=0; i<file->num_tracks; ++i)
+ {
+ FreeTrack(&file->tracks[i]);
+ }
+
+ free(file->tracks);
+ }
+
+ free(file);
+}
+
+midi_file_t *MIDI_LoadFile(char *filename)
+{
+ midi_file_t *file;
+ FILE *stream;
+
+ file = malloc(sizeof(midi_file_t));
+
+ if (file == NULL)
+ {
+ return NULL;
+ }
+
+ file->tracks = NULL;
+ file->num_tracks = 0;
+ file->buffer = NULL;
+ file->buffer_size = 0;
+
+ // Open file
+
+ stream = fopen(filename, "rb");
+
+ if (stream == NULL)
+ {
+ fprintf(stderr, "MIDI_LoadFile: Failed to open '%s'\n", filename);
+ MIDI_FreeFile(file);
+ return NULL;
+ }
+
+ // Read MIDI file header
+
+ if (!ReadFileHeader(file, stream))
+ {
+ fclose(stream);
+ MIDI_FreeFile(file);
+ return NULL;
+ }
+
+ // Read all tracks:
+
+ if (!ReadAllTracks(file, stream))
+ {
+ fclose(stream);
+ MIDI_FreeFile(file);
+ return NULL;
+ }
+
+ fclose(stream);
+
+ return file;
+}
+
+// Get the number of tracks in a MIDI file.
+
+unsigned int MIDI_NumTracks(midi_file_t *file)
+{
+ return file->num_tracks;
+}
+
+// Start iterating over the events in a track.
+
+midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track)
+{
+ midi_track_iter_t *iter;
+
+ assert(track < file->num_tracks);
+
+ iter = malloc(sizeof(*iter));
+ iter->track = &file->tracks[track];
+ iter->position = 0;
+
+ return iter;
+}
+
+void MIDI_FreeIterator(midi_track_iter_t *iter)
+{
+ free(iter);
+}
+
+// Get the time until the next MIDI event in a track.
+
+unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter)
+{
+ if (iter->position < iter->track->num_events)
+ {
+ midi_event_t *next_event;
+
+ next_event = &iter->track->events[iter->position];
+
+ return next_event->delta_time;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Get a pointer to the next MIDI event.
+
+int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event)
+{
+ if (iter->position < iter->track->num_events)
+ {
+ *event = &iter->track->events[iter->position];
+ ++iter->position;
+
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+unsigned int MIDI_GetFileTimeDivision(midi_file_t *file)
+{
+ return file->header.time_division;
+}
+
+void MIDI_RestartIterator(midi_track_iter_t *iter)
+{
+ iter->position = 0;
+}
+
+#ifdef TEST
+
+static char *MIDI_EventTypeToString(midi_event_type_t event_type)
+{
+ switch (event_type)
+ {
+ case MIDI_EVENT_NOTE_OFF:
+ return "MIDI_EVENT_NOTE_OFF";
+ case MIDI_EVENT_NOTE_ON:
+ return "MIDI_EVENT_NOTE_ON";
+ case MIDI_EVENT_AFTERTOUCH:
+ return "MIDI_EVENT_AFTERTOUCH";
+ case MIDI_EVENT_CONTROLLER:
+ return "MIDI_EVENT_CONTROLLER";
+ case MIDI_EVENT_PROGRAM_CHANGE:
+ return "MIDI_EVENT_PROGRAM_CHANGE";
+ case MIDI_EVENT_CHAN_AFTERTOUCH:
+ return "MIDI_EVENT_CHAN_AFTERTOUCH";
+ case MIDI_EVENT_PITCH_BEND:
+ return "MIDI_EVENT_PITCH_BEND";
+ case MIDI_EVENT_SYSEX:
+ return "MIDI_EVENT_SYSEX";
+ case MIDI_EVENT_SYSEX_SPLIT:
+ return "MIDI_EVENT_SYSEX_SPLIT";
+ case MIDI_EVENT_META:
+ return "MIDI_EVENT_META";
+
+ default:
+ return "(unknown)";
+ }
+}
+
+void PrintTrack(midi_track_t *track)
+{
+ midi_event_t *event;
+ unsigned int i;
+
+ for (i=0; i<track->num_events; ++i)
+ {
+ event = &track->events[i];
+
+ if (event->delta_time > 0)
+ {
+ printf("Delay: %i ticks\n", event->delta_time);
+ }
+
+ printf("Event type: %s (%i)\n",
+ MIDI_EventTypeToString(event->event_type),
+ event->event_type);
+
+ switch(event->event_type)
+ {
+ case MIDI_EVENT_NOTE_OFF:
+ case MIDI_EVENT_NOTE_ON:
+ case MIDI_EVENT_AFTERTOUCH:
+ case MIDI_EVENT_CONTROLLER:
+ case MIDI_EVENT_PROGRAM_CHANGE:
+ case MIDI_EVENT_CHAN_AFTERTOUCH:
+ case MIDI_EVENT_PITCH_BEND:
+ printf("\tChannel: %i\n", event->data.channel.channel);
+ printf("\tParameter 1: %i\n", event->data.channel.param1);
+ printf("\tParameter 2: %i\n", event->data.channel.param2);
+ break;
+
+ case MIDI_EVENT_SYSEX:
+ case MIDI_EVENT_SYSEX_SPLIT:
+ printf("\tLength: %i\n", event->data.sysex.length);
+ break;
+
+ case MIDI_EVENT_META:
+ printf("\tMeta type: %i\n", event->data.meta.type);
+ printf("\tLength: %i\n", event->data.meta.length);
+ break;
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ midi_file_t *file;
+ unsigned int i;
+
+ if (argc < 2)
+ {
+ printf("Usage: %s <filename>\n", argv[0]);
+ exit(1);
+ }
+
+ file = MIDI_LoadFile(argv[1]);
+
+ if (file == NULL)
+ {
+ fprintf(stderr, "Failed to open %s\n", argv[1]);
+ exit(1);
+ }
+
+ for (i=0; i<file->num_tracks; ++i)
+ {
+ printf("\n== Track %i ==\n\n", i);
+
+ PrintTrack(&file->tracks[i]);
+ }
+
+ return 0;
+}
+
+#endif
+
diff --git a/src/midifile.h b/src/midifile.h
new file mode 100644
index 00000000..4ee0ddb2
--- /dev/null
+++ b/src/midifile.h
@@ -0,0 +1,175 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2009 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:
+// MIDI file parsing.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef MIDIFILE_H
+#define MIDIFILE_H
+
+typedef struct midi_file_s midi_file_t;
+typedef struct midi_track_iter_s midi_track_iter_t;
+
+#define MIDI_CHANNELS_PER_TRACK 16
+
+typedef enum
+{
+ MIDI_EVENT_NOTE_OFF = 0x80,
+ MIDI_EVENT_NOTE_ON = 0x90,
+ MIDI_EVENT_AFTERTOUCH = 0xa0,
+ MIDI_EVENT_CONTROLLER = 0xb0,
+ MIDI_EVENT_PROGRAM_CHANGE = 0xc0,
+ MIDI_EVENT_CHAN_AFTERTOUCH = 0xd0,
+ MIDI_EVENT_PITCH_BEND = 0xe0,
+
+ MIDI_EVENT_SYSEX = 0xf0,
+ MIDI_EVENT_SYSEX_SPLIT = 0xf7,
+ MIDI_EVENT_META = 0xff,
+} midi_event_type_t;
+
+typedef enum
+{
+ MIDI_CONTROLLER_BANK_SELECT = 0x0,
+ MIDI_CONTROLLER_MODULATION = 0x1,
+ MIDI_CONTROLLER_BREATH_CONTROL = 0x2,
+ MIDI_CONTROLLER_FOOT_CONTROL = 0x3,
+ MIDI_CONTROLLER_PORTAMENTO = 0x4,
+ MIDI_CONTROLLER_DATA_ENTRY = 0x5,
+
+ MIDI_CONTROLLER_MAIN_VOLUME = 0x7,
+ MIDI_CONTROLLER_PAN = 0xa
+} midi_controller_t;
+
+typedef enum
+{
+ MIDI_META_SEQUENCE_NUMBER = 0x0,
+
+ MIDI_META_TEXT = 0x1,
+ MIDI_META_COPYRIGHT = 0x2,
+ MIDI_META_TRACK_NAME = 0x3,
+ MIDI_META_INSTR_NAME = 0x4,
+ MIDI_META_LYRICS = 0x5,
+ MIDI_META_MARKER = 0x6,
+ MIDI_META_CUE_POINT = 0x7,
+
+ MIDI_META_CHANNEL_PREFIX = 0x20,
+ MIDI_META_END_OF_TRACK = 0x2f,
+
+ MIDI_META_SET_TEMPO = 0x51,
+ MIDI_META_SMPTE_OFFSET = 0x54,
+ MIDI_META_TIME_SIGNATURE = 0x58,
+ MIDI_META_KEY_SIGNATURE = 0x59,
+ MIDI_META_SEQUENCER_SPECIFIC = 0x7f,
+} midi_meta_event_type_t;
+
+typedef struct
+{
+ // Meta event type:
+
+ unsigned int type;
+
+ // Length:
+
+ unsigned int length;
+
+ // Meta event data:
+
+ byte *data;
+} midi_meta_event_data_t;
+
+typedef struct
+{
+ // Length:
+
+ unsigned int length;
+
+ // Event data:
+
+ byte *data;
+} midi_sysex_event_data_t;
+
+typedef struct
+{
+ // The channel number to which this applies:
+
+ unsigned int channel;
+
+ // Extra parameters:
+
+ unsigned int param1;
+ unsigned int param2;
+} midi_channel_event_data_t;
+
+typedef struct
+{
+ // Time between the previous event and this event.
+ unsigned int delta_time;
+
+ // Type of event:
+ midi_event_type_t event_type;
+
+ union
+ {
+ midi_channel_event_data_t channel;
+ midi_meta_event_data_t meta;
+ midi_sysex_event_data_t sysex;
+ } data;
+} midi_event_t;
+
+// Load a MIDI file.
+
+midi_file_t *MIDI_LoadFile(char *filename);
+
+// Free a MIDI file.
+
+void MIDI_FreeFile(midi_file_t *file);
+
+// Get the time division value from the MIDI header.
+
+unsigned int MIDI_GetFileTimeDivision(midi_file_t *file);
+
+// Get the number of tracks in a MIDI file.
+
+unsigned int MIDI_NumTracks(midi_file_t *file);
+
+// Start iterating over the events in a track.
+
+midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track_num);
+
+// Free an iterator.
+
+void MIDI_FreeIterator(midi_track_iter_t *iter);
+
+// Get the time until the next MIDI event in a track.
+
+unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter);
+
+// Get a pointer to the next MIDI event.
+
+int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event);
+
+// Reset an iterator to the beginning of a track.
+
+void MIDI_RestartIterator(midi_track_iter_t *iter);
+
+#endif /* #ifndef MIDIFILE_H */
+
diff --git a/src/net_client.c b/src/net_client.c
index 131397e9..a1697944 100644
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -196,7 +196,8 @@ static void NET_CL_PlayerQuitGame(player_t *player)
// Do this the same way as Vanilla Doom does, to allow dehacked
// replacements of this message
- strcpy(exitmsg, DEH_String("Player 1 left the game"));
+ strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg));
+ exitmsg[sizeof(exitmsg) - 1] = '\0';
exitmsg[7] += player - players;
diff --git a/src/setup/.gitignore b/src/setup/.gitignore
index 37c8e4c1..f41d11c7 100644
--- a/src/setup/.gitignore
+++ b/src/setup/.gitignore
@@ -1,8 +1,7 @@
Makefile.in
Makefile
.deps
-chocolate-setup
+setup-manifest.xml
*.rc
-*.exe
tags
TAGS
diff --git a/src/setup/joystick.c b/src/setup/joystick.c
index 0094dd81..fbe3a3f3 100644
--- a/src/setup/joystick.c
+++ b/src/setup/joystick.c
@@ -425,6 +425,8 @@ void ConfigJoystick(void)
AddJoystickControl(button_table, "Strafe Left", &joybstrafeleft);
AddJoystickControl(button_table, "Strafe Right", &joybstraferight);
+ AddJoystickControl(button_table, "Previous weapon", &joybprevweapon);
+ AddJoystickControl(button_table, "Next weapon", &joybnextweapon);
if (gamemission == hexen)
{
diff --git a/src/setup/keyboard.c b/src/setup/keyboard.c
index ce3865b3..7ee523bb 100644
--- a/src/setup/keyboard.c
+++ b/src/setup/keyboard.c
@@ -49,7 +49,7 @@ static int *controls[] = { &key_left, &key_right, &key_up, &key_down,
&key_weapon1, &key_weapon2, &key_weapon3,
&key_weapon4, &key_weapon5, &key_weapon6,
&key_weapon7, &key_weapon8,
- NULL };
+ &key_prevweapon, &key_nextweapon, NULL };
static int *menu_nav[] = { &key_menu_activate, &key_menu_up, &key_menu_down,
&key_menu_left, &key_menu_right, &key_menu_back,
@@ -57,10 +57,12 @@ static int *menu_nav[] = { &key_menu_activate, &key_menu_up, &key_menu_down,
static int *shortcuts[] = { &key_menu_help, &key_menu_save, &key_menu_load,
&key_menu_volume, &key_menu_detail, &key_menu_qsave,
- &key_menu_endgame, &key_menu_messages,
+ &key_menu_endgame, &key_menu_messages, &key_spy,
&key_menu_qload, &key_menu_quit, &key_menu_gamma,
&key_menu_incscreen, &key_menu_decscreen,
- &key_message_refresh, NULL };
+ &key_message_refresh, &key_multi_msg,
+ &key_multi_msgplayer[0], &key_multi_msgplayer[1],
+ &key_multi_msgplayer[2], &key_multi_msgplayer[3] };
static int *map_keys[] = { &key_map_north, &key_map_south, &key_map_east,
&key_map_west, &key_map_zoomin, &key_map_zoomout,
@@ -240,6 +242,8 @@ static void ConfigExtraKeys(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
AddKeyControl(table, "Weapon 6", &key_weapon6);
AddKeyControl(table, "Weapon 7", &key_weapon7);
AddKeyControl(table, "Weapon 8", &key_weapon8);
+ AddKeyControl(table, "Previous weapon", &key_prevweapon);
+ AddKeyControl(table, "Next weapon", &key_nextweapon);
}
static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
@@ -280,14 +284,15 @@ static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
AddKeyControl(table, "Quick load", &key_menu_qload);
AddKeyControl(table, "Quit game", &key_menu_quit);
AddKeyControl(table, "Toggle gamma", &key_menu_gamma);
+ AddKeyControl(table, "Multiplayer spy", &key_spy);
AddKeyControl(table, "Increase screen size", &key_menu_incscreen);
AddKeyControl(table, "Decrease screen size", &key_menu_decscreen);
AddKeyControl(table, "Display last message", &key_message_refresh);
+ AddKeyControl(table, "Finish recording demo", &key_demo_quit);
AddSectionLabel(table, "Map", true);
-
AddKeyControl(table, "Toggle map", &key_map_toggle);
AddKeyControl(table, "Zoom in", &key_map_zoomin);
AddKeyControl(table, "Zoom out", &key_map_zoomout);
@@ -301,6 +306,20 @@ static void OtherKeysDialog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
AddKeyControl(table, "Mark location", &key_map_mark);
AddKeyControl(table, "Clear all marks", &key_map_clearmark);
+ AddSectionLabel(table, "Multiplayer", true);
+
+ AddKeyControl(table, "Send message", &key_multi_msg);
+ AddKeyControl(table, "- to green", &key_multi_msgplayer[0]);
+ AddKeyControl(table, "- to indigo", &key_multi_msgplayer[1]);
+ AddKeyControl(table, "- to brown", &key_multi_msgplayer[2]);
+ AddKeyControl(table, "- to red", &key_multi_msgplayer[3]);
+
+ TXT_AddWidgets(table, TXT_NewStrut(0, 1),
+ TXT_NewStrut(0, 1),
+ TXT_NewLabel(" - Map - "),
+ TXT_NewStrut(0, 0),
+ NULL);
+
scrollpane = TXT_NewScrollPane(0, 13, table);
TXT_AddWidget(window, scrollpane);
diff --git a/src/setup/keyboard.h b/src/setup/keyboard.h
index 2797ba8f..12059bf8 100644
--- a/src/setup/keyboard.h
+++ b/src/setup/keyboard.h
@@ -22,59 +22,6 @@
#ifndef SETUP_KEYBOARD_H
#define SETUP_KEYBOARD_H
-// Menu keys:
-
-extern int key_menu_activate;
-extern int key_menu_up;
-extern int key_menu_down;
-extern int key_menu_left;
-extern int key_menu_right;
-extern int key_menu_back;
-extern int key_menu_forward;
-extern int key_menu_confirm;
-extern int key_menu_abort;
-
-extern int key_menu_help;
-extern int key_menu_save;
-extern int key_menu_load;
-extern int key_menu_volume;
-extern int key_menu_detail;
-extern int key_menu_qsave;
-extern int key_menu_endgame;
-extern int key_menu_messages;
-extern int key_menu_qload;
-extern int key_menu_quit;
-extern int key_menu_gamma;
-
-extern int key_menu_incscreen;
-extern int key_menu_decscreen;
-
-// Automap keys:
-
-extern int key_map_north;
-extern int key_map_south;
-extern int key_map_east;
-extern int key_map_west;
-extern int key_map_zoomin;
-extern int key_map_zoomout;
-extern int key_map_toggle;
-extern int key_map_maxzoom;
-extern int key_map_follow;
-extern int key_map_grid;
-extern int key_map_mark;
-extern int key_map_clearmark;
-
-// Weapon keys:
-
-extern int key_weapon1;
-extern int key_weapon2;
-extern int key_weapon3;
-extern int key_weapon4;
-extern int key_weapon5;
-extern int key_weapon6;
-extern int key_weapon7;
-extern int key_weapon8;
-
void ConfigKeyboard(void);
void BindKeyboardVariables(void);
diff --git a/src/setup/mainmenu.c b/src/setup/mainmenu.c
index 46e4b4e6..c3cb7db5 100644
--- a/src/setup/mainmenu.c
+++ b/src/setup/mainmenu.c
@@ -46,6 +46,64 @@
#include "multiplayer.h"
#include "sound.h"
+static const int cheat_sequence[] =
+{
+ KEY_UPARROW, KEY_UPARROW, KEY_DOWNARROW, KEY_DOWNARROW,
+ KEY_LEFTARROW, KEY_RIGHTARROW, KEY_LEFTARROW, KEY_RIGHTARROW,
+ 'b', 'a', KEY_ENTER, 0
+};
+
+static unsigned int cheat_sequence_index = 0;
+
+// I think these are good "sensible" defaults:
+
+static void SensibleDefaults(void)
+{
+#if 0
+ // TODO for raven-branch
+ key_up = 'w';
+ key_down = 's';
+ key_strafeleft = 'a';
+ key_straferight = 'd';
+ mousebprevweapon = 4;
+ mousebnextweapon = 3;
+ snd_musicdevice = 3;
+ joybspeed = 29;
+ vanilla_savegame_limit = 0;
+ vanilla_keyboard_mapping = 0;
+ vanilla_demo_limit = 0;
+ show_endoom = 0;
+ dclick_use = 0;
+ novert = 1;
+#endif
+}
+
+static int MainMenuKeyPress(txt_window_t *window, int key, void *user_data)
+{
+ if (key == cheat_sequence[cheat_sequence_index])
+ {
+ ++cheat_sequence_index;
+
+ if (cheat_sequence[cheat_sequence_index] == 0)
+ {
+ SensibleDefaults();
+ cheat_sequence_index = 0;
+
+ window = TXT_NewWindow(NULL);
+ TXT_AddWidget(window, TXT_NewLabel(" \x01 "));
+ TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
+
+ return 1;
+ }
+ }
+ else
+ {
+ cheat_sequence_index = 0;
+ }
+
+ return 0;
+}
+
static void DoQuit(void *widget, void *dosave)
{
if (dosave != NULL)
@@ -174,6 +232,8 @@ void MainMenu(void)
quit_action = TXT_NewWindowAction(KEY_ESCAPE, "Quit");
TXT_SignalConnect(quit_action, "pressed", QuitConfirm, NULL);
TXT_SetWindowAction(window, TXT_HORIZ_LEFT, quit_action);
+
+ TXT_SetKeyListener(window, MainMenuKeyPress, NULL);
}
//
diff --git a/src/setup/mouse.c b/src/setup/mouse.c
index d464261f..5b555f88 100644
--- a/src/setup/mouse.c
+++ b/src/setup/mouse.c
@@ -36,7 +36,7 @@ static int usemouse = 1;
static int novert = 0;
static int mouseSensitivity = 5;
-static float mouse_acceleration = 1.0;
+static float mouse_acceleration = 2.0;
static int mouse_threshold = 10;
static int grabmouse = 1;
@@ -48,7 +48,9 @@ static int *all_mouse_buttons[] = {
&mousebstraferight,
&mousebbackward,
&mousebuse,
- &mousebjump
+ &mousebjump,
+ &mousebprevweapon,
+ &mousebnextweapon
};
static void MouseSetCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(variable))
@@ -103,6 +105,9 @@ static void ConfigExtraButtons(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
{
AddMouseControl(buttons_table, "Jump", &mousebjump);
}
+
+ AddMouseControl(buttons_table, "Previous weapon", &mousebprevweapon);
+ AddMouseControl(buttons_table, "Next weapon", &mousebnextweapon);
}
void ConfigMouse(void)
diff --git a/src/setup/multiplayer.c b/src/setup/multiplayer.c
index f3b3221d..24cd0670 100644
--- a/src/setup/multiplayer.c
+++ b/src/setup/multiplayer.c
@@ -29,6 +29,7 @@
#include "d_iwad.h"
#include "m_config.h"
#include "doom/d_englsh.h"
+#include "m_controls.h"
#include "multiplayer.h"
#include "mode.h"
@@ -863,5 +864,39 @@ void BindMultiplayerVariables(void)
sprintf(buf, "chatmacro%i", i);
M_BindVariable(buf, &chat_macros[i]);
}
+
+ switch (gamemission)
+ {
+ case doom:
+ M_BindChatControls(4);
+ key_multi_msgplayer[0] = 'g';
+ key_multi_msgplayer[1] = 'i';
+ key_multi_msgplayer[2] = 'b';
+ key_multi_msgplayer[3] = 'r';
+ break;
+
+ case heretic:
+ M_BindChatControls(4);
+ key_multi_msgplayer[0] = 'g';
+ key_multi_msgplayer[1] = 'y';
+ key_multi_msgplayer[2] = 'r';
+ key_multi_msgplayer[3] = 'b';
+ break;
+
+ case hexen:
+ M_BindChatControls(8);
+ key_multi_msgplayer[0] = 'b';
+ key_multi_msgplayer[1] = 'r';
+ key_multi_msgplayer[2] = 'y';
+ key_multi_msgplayer[3] = 'g';
+ key_multi_msgplayer[4] = 'j';
+ key_multi_msgplayer[5] = 'w';
+ key_multi_msgplayer[6] = 'h';
+ key_multi_msgplayer[7] = 'p';
+ break;
+
+ default:
+ break;
+ }
}
diff --git a/src/setup/sound.c b/src/setup/sound.c
index 45787eba..d8dc129e 100644
--- a/src/setup/sound.c
+++ b/src/setup/sound.c
@@ -40,17 +40,18 @@ typedef enum
NUM_SFXMODES
} sfxmode_t;
-static char *sfxmode_strings[] =
+static char *sfxmode_strings[] =
{
"Disabled",
"Digital",
"PC speaker"
};
-typedef enum
+typedef enum
{
MUSICMODE_DISABLED,
- MUSICMODE_MIDI,
+ MUSICMODE_OPL,
+ MUSICMODE_NATIVE,
MUSICMODE_CD,
NUM_MUSICMODES
} musicmode_t;
@@ -58,15 +59,17 @@ typedef enum
static char *musicmode_strings[] =
{
"Disabled",
- "MIDI",
+ "OPL (Adlib/SB)",
+ "Native MIDI",
"CD audio"
};
// Config file variables:
int snd_sfxdevice = SNDDEVICE_SB;
-int snd_musicdevice = SNDDEVICE_SB;
+int snd_musicdevice = SNDDEVICE_GENMIDI;
int snd_samplerate = 22050;
+int opl_io_port = 0x388;
static int numChannels = 8;
static int sfxVolume = 15;
@@ -108,7 +111,10 @@ static void UpdateSndDevices(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(data))
case MUSICMODE_DISABLED:
snd_musicdevice = SNDDEVICE_NONE;
break;
- case MUSICMODE_MIDI:
+ case MUSICMODE_NATIVE:
+ snd_musicdevice = SNDDEVICE_GENMIDI;
+ break;
+ case MUSICMODE_OPL:
snd_musicdevice = SNDDEVICE_SB;
break;
case MUSICMODE_CD:
@@ -139,20 +145,26 @@ void ConfigSound(void)
{
snd_sfxmode = SFXMODE_DISABLED;
}
-
+
// Is music enabled?
- if (snd_musicdevice == SNDDEVICE_NONE)
+ if (snd_musicdevice == SNDDEVICE_GENMIDI)
{
- snd_musicmode = MUSICMODE_DISABLED;
+ snd_musicmode = MUSICMODE_NATIVE;
}
else if (snd_musicmode == SNDDEVICE_CD)
{
snd_musicmode = MUSICMODE_CD;
}
+ else if (snd_musicdevice == SNDDEVICE_SB
+ || snd_musicdevice == SNDDEVICE_ADLIB
+ || snd_musicdevice == SNDDEVICE_AWE32)
+ {
+ snd_musicmode = MUSICMODE_OPL;
+ }
else
{
- snd_musicmode = MUSICMODE_MIDI;
+ snd_musicmode = MUSICMODE_DISABLED;
}
// Doom has PC speaker sound effects, but others do not:
@@ -188,7 +200,7 @@ void ConfigSound(void)
music_table = TXT_NewTable(2),
NULL);
- TXT_SetColumnWidths(sfx_table, 20, 5);
+ TXT_SetColumnWidths(sfx_table, 20, 14);
TXT_AddWidgets(sfx_table,
TXT_NewLabel("Sound effects"),
@@ -209,7 +221,7 @@ void ConfigSound(void)
NULL);
}
- TXT_SetColumnWidths(music_table, 20, 5);
+ TXT_SetColumnWidths(music_table, 20, 14);
TXT_AddWidgets(music_table,
TXT_NewLabel("Music"),
@@ -222,7 +234,6 @@ void ConfigSound(void)
TXT_SignalConnect(sfx_mode_control, "changed", UpdateSndDevices, NULL);
TXT_SignalConnect(music_mode_control, "changed", UpdateSndDevices, NULL);
-
}
void BindSoundVariables(void)
diff --git a/src/setup/txt_keyinput.c b/src/setup/txt_keyinput.c
index e385cc59..483c325f 100644
--- a/src/setup/txt_keyinput.c
+++ b/src/setup/txt_keyinput.c
@@ -111,7 +111,7 @@ static void TXT_KeyInputDrawer(TXT_UNCAST_ARG(key_input), int selected)
if (*key_input->variable == 0)
{
- strcpy(buf, "");
+ strcpy(buf, "(none)");
}
else
{
diff --git a/src/setup/txt_mouseinput.c b/src/setup/txt_mouseinput.c
index 05c89b39..8b87e651 100644
--- a/src/setup/txt_mouseinput.c
+++ b/src/setup/txt_mouseinput.c
@@ -91,7 +91,7 @@ static void GetMouseButtonDescription(int button, char *buf)
strcpy(buf, "MID");
break;
default:
- sprintf(buf, "BUTTON #%i", button);
+ sprintf(buf, "BUTTON #%i", button + 1);
break;
}
}
@@ -153,7 +153,7 @@ static int TXT_MouseInputKeyPress(TXT_UNCAST_ARG(mouse_input), int mouse)
static void TXT_MouseInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b)
{
TXT_CAST_ARG(txt_mouse_input_t, widget);
-
+
// Clicking is like pressing enter
if (b == TXT_MOUSE_LEFT)
diff --git a/src/strife/.gitignore b/src/strife/.gitignore
index 973a0073..d4e88e5a 100644
--- a/src/strife/.gitignore
+++ b/src/strife/.gitignore
@@ -1,9 +1,5 @@
Makefile
Makefile.in
.deps
-*.rc
-chocolate-doom
-chocolate-server
-*.exe
tags
TAGS
diff --git a/src/strife/am_map.c b/src/strife/am_map.c
index b1eaa216..c9d0f659 100644
--- a/src/strife/am_map.c
+++ b/src/strife/am_map.c
@@ -502,7 +502,7 @@ void AM_loadPics(void)
for (i=0;i<10;i++)
{
- sprintf(namebuf, DEH_String("PLMNUM%d"), i);
+ DEH_snprintf(namebuf, 9, "PLMNUM%d", i);
marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
}
@@ -515,7 +515,7 @@ void AM_unloadPics(void)
for (i=0;i<10;i++)
{
- sprintf(namebuf, DEH_String("PLMNUM%d"), i); // haleyjd: Choco change.
+ DEH_snprintf(namebuf, 9, "PLMNUM%d", i);
W_ReleaseLumpName(namebuf);
}
}
@@ -1022,7 +1022,7 @@ AM_drawFline
|| fl->b.x < 0 || fl->b.x >= f_w
|| fl->b.y < 0 || fl->b.y >= f_h)
{
- fprintf(stderr, DEH_String("fuck %d \r"), fuck++);
+ DEH_fprintf(stderr, "fuck %d \r", fuck++);
return;
}
diff --git a/src/strife/d_main.c b/src/strife/d_main.c
index 8dcbcf8c..e7ed01be 100644
--- a/src/strife/d_main.c
+++ b/src/strife/d_main.c
@@ -45,8 +45,8 @@
#include "d_iwad.h"
#include "z_zone.h"
+#include "w_main.h"
#include "w_wad.h"
-#include "w_merge.h"
#include "s_sound.h"
#include "v_video.h"
@@ -384,6 +384,12 @@ void D_BindVariables(void)
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();
@@ -849,7 +855,6 @@ static boolean CheckChex(char *iwadname)
// print title for every printed line
char title[128];
-
static boolean D_AddFile(char *filename)
{
wad_file_t *handle;
@@ -1126,7 +1131,7 @@ void D_DoomMain (void)
I_PrintBanner(PACKAGE_STRING);
- printf (DEH_String("Z_Init: Init zone memory allocation daemon. \n"));
+ DEH_printf("Z_Init: Init zone memory allocation daemon. \n");
Z_Init ();
#ifdef FEATURE_MULTIPLAYER
@@ -1245,7 +1250,7 @@ void D_DoomMain (void)
deathmatch = 2;
if (devparm)
- printf(DEH_String(D_DEVSTR));
+ DEH_printf(D_DEVSTR);
// find which dir to use for config files
@@ -1294,7 +1299,7 @@ void D_DoomMain (void)
scale = 10;
if (scale > 400)
scale = 400;
- printf (DEH_String("turbo scale: %i%%\n"),scale);
+ 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;
@@ -1302,12 +1307,12 @@ void D_DoomMain (void)
}
// init subsystems
- printf(DEH_String("V_Init: allocate screens.\n"));
- V_Init();
+ DEH_printf("V_Init: allocate screens.\n");
+ V_Init ();
// Load configuration files before initialising other subsystems.
// haleyjd 08/22/2010: [STRIFE] - use strife.cfg
- printf(DEH_String("M_LoadDefaults: Load system defaults.\n"));
+ DEH_printf("M_LoadDefaults: Load system defaults.\n");
M_SetConfigFilenames("strife.cfg", PROGRAM_PREFIX "strife.cfg");
D_BindVariables();
M_LoadDefaults();
@@ -1315,160 +1320,9 @@ void D_DoomMain (void)
// Save configuration at exit.
I_AtExit(M_SaveDefaults, false);
- printf (DEH_String("W_Init: Init WADfiles.\n"));
+ DEH_printf("W_Init: Init WADfiles.\n");
D_AddFile(iwadfile);
-
-#ifdef FEATURE_WAD_MERGE
-
- // Merged PWADs are loaded first, because they are supposed to be
- // modified IWADs.
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of deutex's -merge option, merging a PWAD
- // into the main IWAD. Multiple files may be specified.
- //
-
- p = M_CheckParm("-merge");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging %s\n", filename);
- W_MergeFile(filename);
- }
- }
-
- // NWT-style merging:
-
- // NWT's -merge option:
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of NWT's -merge option. Multiple files
- // may be specified.
-
- p = M_CheckParm("-nwtmerge");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" performing NWT-style merge of %s\n", filename);
- W_NWTDashMerge(filename);
- }
- }
-
- // Add flats
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of NWT's -af option, merging flats into
- // the main IWAD directory. Multiple files may be specified.
- //
-
- p = M_CheckParm("-af");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging flats from %s\n", filename);
- W_NWTMergeFile(filename, W_NWT_MERGE_FLATS);
- }
- }
-
- //!
- // @arg <files>
- // @category mod
- //
- // Simulates the behavior of NWT's -as option, merging sprites
- // into the main IWAD directory. Multiple files may be specified.
- //
-
- p = M_CheckParm("-as");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging sprites from %s\n", filename);
- W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES);
- }
- }
-
- //!
- // @arg <files>
- // @category mod
- //
- // Equivalent to "-af <files> -as <files>".
- //
-
- p = M_CheckParm("-aa");
-
- if (p > 0)
- {
- for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- printf(" merging sprites and flats from %s\n", filename);
- W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES | W_NWT_MERGE_FLATS);
- }
- }
-
-#endif
-
- //!
- // @arg <files>
- // @vanilla
- //
- // Load the specified PWAD files.
- //
-
- p = M_CheckParm ("-file");
- if (p)
- {
- // the parms after p are wadfile/lump names,
- // until end of parms or another - preceded parm
- modifiedgame = true; // homebrew levels
- while (++p != myargc && myargv[p][0] != '-')
- {
- char *filename;
-
- filename = D_TryFindWADByName(myargv[p]);
-
- D_AddFile(filename);
- }
- }
-
- // Debug:
-// W_PrintDirectory();
+ modifiedgame = W_ParseCommandLine();
// add any files specified on the command line with -file wadfile
// to the wad list
@@ -1664,8 +1518,8 @@ void D_DoomMain (void)
if (p && p < myargc-1 && deathmatch)
{
- printf(DEH_String("Austin Virtual Gaming: Levels will end "
- "after 20 minutes\n"));
+ DEH_printf("Austin Virtual Gaming: Levels will end "
+ "after 20 minutes\n");
timelimit = 20;
}
@@ -1750,17 +1604,17 @@ void D_DoomMain (void)
// haleyjd 08/28/10: Init Choco Strife stuff.
D_InitChocoStrife();
- printf (DEH_String("M_Init: Init miscellaneous info.\n"));
+ DEH_printf("M_Init: Init miscellaneous info.\n");
M_Init ();
// haleyjd 08/22/2010: [STRIFE] Modified string to match binary
- printf (DEH_String("R_Init: Loading Graphics - "));
+ DEH_printf("R_Init: Loading Graphics - ");
R_Init ();
- printf (DEH_String("\nP_Init: Init Playloop state.\n"));
+ DEH_printf("\nP_Init: Init Playloop state.\n");
P_Init ();
- printf (DEH_String("I_Init: Setting up machine state.\n"));
+ DEH_printf("I_Init: Setting up machine state.\n");
I_CheckIsScreensaver();
I_InitTimer();
I_InitJoystick();
@@ -1770,18 +1624,18 @@ void D_DoomMain (void)
NET_Init ();
#endif
- printf (DEH_String("S_Init: Setting up sound.\n"));
+ DEH_printf("S_Init: Setting up sound.\n");
S_Init (sfxVolume * 8, musicVolume * 8);
- printf (DEH_String("D_CheckNetGame: Checking network game status.\n"));
+ DEH_printf("D_CheckNetGame: Checking network game status.\n");
D_CheckNetGame ();
PrintGameVersion();
- printf (DEH_String("HU_Init: Setting up heads up display.\n"));
+ DEH_printf("HU_Init: Setting up heads up display.\n");
HU_Init ();
- printf (DEH_String("ST_Init: Init status bar.\n"));
+ DEH_printf("ST_Init: Init status bar.\n");
ST_Init ();
// If Doom II without a MAP01 lump, this is a store demo.
diff --git a/src/strife/d_net.c b/src/strife/d_net.c
index c8742c71..bacc4e23 100644
--- a/src/strife/d_net.c
+++ b/src/strife/d_net.c
@@ -374,17 +374,17 @@ void D_CheckNetGame (void)
++num_players;
}
- printf (DEH_String("startskill %i deathmatch: %i startmap: %i startepisode: %i\n"),
- startskill, deathmatch, startmap, startepisode);
+ DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
+ startskill, deathmatch, startmap, startepisode);
- printf(DEH_String("player %i of %i (%i nodes)\n"),
- consoleplayer+1, num_players, num_players);
+ 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)
{
- printf(DEH_String("Levels will end after %d minute"),timelimit);
+ DEH_printf("Levels will end after %d minute", timelimit);
if (timelimit > 1)
printf("s");
printf(".\n");
diff --git a/src/strife/f_finale.c b/src/strife/f_finale.c
index 9e0aca93..68c07af1 100644
--- a/src/strife/f_finale.c
+++ b/src/strife/f_finale.c
@@ -665,7 +665,7 @@ void F_BunnyScroll (void)
laststage = stage;
}
- sprintf (name, DEH_String("END%i"), stage);
+ DEH_snprintf(name, 10, "END%i", stage);
V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
(SCREENHEIGHT - 8 * 8) / 2,
W_CacheLumpName (name,PU_CACHE));
diff --git a/src/strife/g_game.c b/src/strife/g_game.c
index 25838468..42c8bdd3 100644
--- a/src/strife/g_game.c
+++ b/src/strife/g_game.c
@@ -183,14 +183,40 @@ static int *weapon_keys[] = {
&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[4];
+static boolean mousearray[MAX_MOUSE_BUTTONS + 1];
static boolean *mousebuttons = &mousearray[1]; // allow [-1]
// mouse values are used once
@@ -204,8 +230,6 @@ static int dclicktime2;
static boolean dclickstate2;
static int dclicks2;
-#define MAX_JOY_BUTTONS 20
-
// joystick values are repeated
static int joyxmove;
static int joyymove;
@@ -344,7 +368,55 @@ int G_CmdChecksum (ticcmd_t* cmd)
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
@@ -503,20 +575,34 @@ void G_BuildTiccmd (ticcmd_t* cmd)
dclicks = 0;
}
- // chainsaw overrides
+ // 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.
- for (i=0; i<arrlen(weapon_keys); ++i)
+ if (next_weapon != 0)
{
- int key = *weapon_keys[i];
+ i = G_NextWeapon(next_weapon);
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i << BT_WEAPONSHIFT;
+ next_weapon = 0;
+ }
+ else
+ {
+ // Check weapon keys.
- if (gamekeydown[key])
+ for (i=0; i<arrlen(weapon_keys); ++i)
{
- cmd->buttons |= BT_CHANGE;
- cmd->buttons |= i<<BT_WEAPONSHIFT;
- break;
+ int key = *weapon_keys[i];
+
+ if (gamekeydown[key])
+ {
+ cmd->buttons |= BT_CHANGE;
+ cmd->buttons |= i<<BT_WEAPONSHIFT;
+ break;
+ }
}
}
-
+
// mouse
if (mousebuttons[mousebforward])
{
@@ -697,7 +783,6 @@ void G_DoLoadLevel (void)
P_DialogLoad(); // villsa [STRIFE]
}
-
static void SetJoyButtons(unsigned int buttons_mask)
{
@@ -705,10 +790,54 @@ static void SetJoyButtons(unsigned int buttons_mask)
for (i=0; i<MAX_JOY_BUTTONS; ++i)
{
- joybuttons[i] = (buttons_mask & (1 << i)) != 0;
+ 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.
@@ -717,7 +846,7 @@ 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_F12 && (singledemo || !deathmatch) )
+ && ev->data1 == key_spy && (singledemo || !deathmatch) )
{
// spy mode
do
@@ -777,6 +906,18 @@ boolean G_Responder (event_t* ev)
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:
@@ -797,9 +938,7 @@ boolean G_Responder (event_t* ev)
return false; // always let key up events filter down
case ev_mouse:
- mousebuttons[0] = ev->data1 & 1;
- mousebuttons[1] = ev->data1 & 2;
- mousebuttons[2] = ev->data1 & 4;
+ SetMouseButtons(ev->data1);
mousex = ev->data2*(mouseSensitivity+5)/10;
mousey = ev->data3*(mouseSensitivity+5)/10;
return true; // eat events
@@ -1416,6 +1555,8 @@ void G_DoLoadGame (void)
return;
}
+ savegame_error = false;
+
if (!P_ReadSaveGameHeader())
{
fclose(save_stream);
@@ -1483,6 +1624,8 @@ void G_DoSaveGame (void)
return;
}
+ savegame_error = false;
+
P_WriteSaveGameHeader(savedescription);
P_ArchivePlayers ();
@@ -1778,7 +1921,7 @@ void G_WriteDemoTiccmd (ticcmd_t* cmd)
{
byte *demo_start;
- if (gamekeydown['q']) // press q to end demo recording
+ if (gamekeydown[key_demo_quit]) // press q to end demo recording
G_CheckDemoStatus ();
demo_start = demo_p;
diff --git a/src/strife/hu_stuff.c b/src/strife/hu_stuff.c
index 3ddf402e..0358bd63 100644
--- a/src/strife/hu_stuff.c
+++ b/src/strife/hu_stuff.c
@@ -178,7 +178,7 @@ void HU_Init(void)
j = HU_FONTSTART;
for (i=0;i<HU_FONTSIZE;i++)
{
- sprintf(buffer, DEH_String("STCFN%.3d"), j++);
+ DEH_snprintf(buffer, 9, "STCFN%.3d", j++);
hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
}
@@ -383,14 +383,6 @@ boolean HU_Responder(event_t *ev)
int i;
int numplayers;
- static char destination_keys[MAXPLAYERS] =
- {
- HUSTR_KEYGREEN,
- HUSTR_KEYINDIGO,
- HUSTR_KEYBROWN,
- HUSTR_KEYRED
- };
-
static int num_nobrainers = 0;
numplayers = 0;
@@ -419,7 +411,7 @@ boolean HU_Responder(event_t *ev)
message_counter = HU_MSGTIMEOUT;
eatkey = true;
}
- else if (netgame && ev->data2 == HU_INPUTTOGGLE)
+ else if (netgame && ev->data2 == key_multi_msg)
{
eatkey = chat_on = true;
HUlib_resetIText(&w_chat);
@@ -429,7 +421,7 @@ boolean HU_Responder(event_t *ev)
{
for (i=0; i<MAXPLAYERS ; i++)
{
- if (ev->data2 == destination_keys[i])
+ if (ev->data2 == key_multi_msgplayer[i])
{
if (playeringame[i] && i!=consoleplayer)
{
diff --git a/src/strife/m_menu.c b/src/strife/m_menu.c
index 337c663b..ef868236 100644
--- a/src/strife/m_menu.c
+++ b/src/strife/m_menu.c
@@ -715,7 +715,7 @@ void M_QuickSave(void)
quickSaveSlot = -2; // means to pick a slot now
return;
}
- sprintf(tempstring,DEH_String(QSPROMPT),savegamestrings[quickSaveSlot]);
+ DEH_snprintf(tempstring, 80, QSPROMPT, savegamestrings[quickSaveSlot]);
M_StartMessage(tempstring,M_QuickSaveResponse,true);
}
@@ -747,7 +747,7 @@ void M_QuickLoad(void)
M_StartMessage(DEH_String(QSAVESPOT),NULL,false);
return;
}
- sprintf(tempstring,DEH_String(QLPROMPT),savegamestrings[quickSaveSlot]);
+ DEH_snprintf(tempstring, 80, QLPROMPT, savegamestrings[quickSaveSlot]);
M_StartMessage(tempstring,M_QuickLoadResponse,true);
}
diff --git a/src/strife/p_saveg.c b/src/strife/p_saveg.c
index 6da095e5..52c6bcd5 100644
--- a/src/strife/p_saveg.c
+++ b/src/strife/p_saveg.c
@@ -44,6 +44,7 @@
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
@@ -75,7 +76,7 @@ char *P_SaveGameFile(int slot)
filename = malloc(strlen(savegamedir) + 32);
}
- sprintf(basename, DEH_String(SAVEGAMENAME "%d.dsg"), slot);
+ DEH_snprintf(basename, 32, SAVEGAMENAME "%d.dsg", slot);
sprintf(filename, "%s%s", savegamedir, basename);
@@ -88,14 +89,31 @@ static byte saveg_read8(void)
{
byte result;
- fread(&result, 1, 1, save_stream);
+ 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)
{
- fwrite(&value, 1, 1, save_stream);
+ 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)
diff --git a/src/strife/p_saveg.h b/src/strife/p_saveg.h
index 3a96cc3e..5488289c 100644
--- a/src/strife/p_saveg.h
+++ b/src/strife/p_saveg.h
@@ -64,6 +64,7 @@ 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
index 652d86df..2145c5d5 100644
--- a/src/strife/p_setup.c
+++ b/src/strife/p_setup.c
@@ -33,6 +33,7 @@
#include "deh_main.h"
#include "i_swap.h"
+#include "m_argv.h"
#include "m_bbox.h"
#include "g_game.h"
@@ -76,6 +77,7 @@ line_t* lines;
int numsides;
side_t* sides;
+static int totallines;
// BLOCKMAP
// Created from axis aligned bounding box
@@ -554,7 +556,6 @@ void P_GroupLines (void)
line_t** linebuffer;
int i;
int j;
- int total;
line_t* li;
sector_t* sector;
subsector_t* ss;
@@ -572,21 +573,21 @@ void P_GroupLines (void)
// count number of lines in each sector
li = lines;
- total = 0;
+ totallines = 0;
for (i=0 ; i<numlines ; i++, li++)
{
- total++;
+ totallines++;
li->frontsector->linecount++;
if (li->backsector && li->backsector != li->frontsector)
{
li->backsector->linecount++;
- total++;
+ totallines++;
}
}
// build line tables for each sector
- linebuffer = Z_Malloc (total*sizeof(line_t *), PU_LEVEL, 0);
+ linebuffer = Z_Malloc (totallines*sizeof(line_t *), PU_LEVEL, 0);
for (i=0; i<numsectors; ++i)
{
@@ -663,6 +664,87 @@ void P_GroupLines (void)
}
+// 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
@@ -712,9 +794,9 @@ P_SetupLevel
if ( gamemode == commercial)
{
if (map<10)
- sprintf (lumpname, DEH_String("map0%i"), map);
+ DEH_snprintf(lumpname, 9, "map0%i", map);
else
- sprintf (lumpname, DEH_String("map%i"), map);
+ DEH_snprintf(lumpname, 9, "map%i", map);
}
else
{
@@ -739,9 +821,9 @@ P_SetupLevel
P_LoadSubsectors (lumpnum+ML_SSECTORS);
P_LoadNodes (lumpnum+ML_NODES);
P_LoadSegs (lumpnum+ML_SEGS);
-
- rejectmatrix = W_CacheLumpNum (lumpnum+ML_REJECT,PU_LEVEL);
+
P_GroupLines ();
+ P_LoadReject (lumpnum+ML_REJECT);
bodyqueslot = 0;
deathmatch_p = deathmatchstarts;
diff --git a/src/strife/r_draw.c b/src/strife/r_draw.c
index a09032c7..79c571fe 100644
--- a/src/strife/r_draw.c
+++ b/src/strife/r_draw.c
@@ -600,48 +600,54 @@ int dscount;
// Draws the actual span.
void R_DrawSpan (void)
{
- fixed_t xfrac;
- fixed_t yfrac;
- byte* dest;
- int count;
- int spot;
-
-#ifdef RANGECHECK
+ 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
+ || ds_x2>=SCREENWIDTH
|| (unsigned)ds_y>SCREENHEIGHT)
{
I_Error( "R_DrawSpan: %i to %i at %i",
ds_x1,ds_x2,ds_y);
}
-// dscount++;
-#endif
+// 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);
-
- xfrac = ds_xfrac;
- yfrac = ds_yfrac;
-
dest = ylookup[ds_y] + columnofs[ds_x1];
// We do not check for zero spans here?
- count = ds_x2 - ds_x1;
+ count = ds_x2 - ds_x1;
- do
+ do
{
- // Current texture index in u,v.
- spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
+ // 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]];
- // Next step in u,v.
- xfrac += ds_xstep;
- yfrac += ds_ystep;
-
- } while (count--);
-}
+ position += step;
+
+ } while (count--);
+}
@@ -721,49 +727,54 @@ void R_DrawSpan (void)
//
// Again..
//
-void R_DrawSpanLow (void)
-{
- fixed_t xfrac;
- fixed_t yfrac;
- byte* dest;
- int count;
- int spot;
-
-#ifdef RANGECHECK
+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
+ || ds_x2>=SCREENWIDTH
|| (unsigned)ds_y>SCREENHEIGHT)
{
I_Error( "R_DrawSpan: %i to %i at %i",
ds_x1,ds_x2,ds_y);
}
// dscount++;
-#endif
-
- xfrac = ds_xfrac;
- yfrac = ds_yfrac;
-
- count = (ds_x2 - ds_x1);
+#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
- {
- spot = ((yfrac>>(16-6))&(63*64)) + ((xfrac>>16)&63);
+
+ 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]];
-
- xfrac += ds_xstep;
- yfrac += ds_ystep;
+ *dest++ = ds_colormap[ds_source[spot]];
- } while (count--);
+ position += step;
+
+ } while (count--);
}
//
diff --git a/src/strife/st_stuff.c b/src/strife/st_stuff.c
index 3b4ff0fb..1af8a485 100644
--- a/src/strife/st_stuff.c
+++ b/src/strife/st_stuff.c
@@ -767,10 +767,10 @@ static void ST_loadUnloadGraphics(load_callback_t callback)
// Load the numbers, green and yellow
for (i=0;i<10;i++)
{
- sprintf(namebuf, DEH_String("INVFONG%d"), i);
+ DEH_snprintf(namebuf, 9, "INVFONG%d", i);
callback(namebuf, &invfontg[i]);
- sprintf(namebuf, DEH_String("INVFONY%d"), i);
+ DEH_snprintf(namebuf, 9, "INVFONY%d", i);
callback(namebuf, &invfonty[i]);
}
diff --git a/src/strife/wi_stuff.c b/src/strife/wi_stuff.c
index 1ae8c9e2..f322e31f 100644
--- a/src/strife/wi_stuff.c
+++ b/src/strife/wi_stuff.c
@@ -1572,16 +1572,16 @@ static void WI_loadUnloadData(load_callback_t callback)
if (gamemode == commercial)
{
for (i=0 ; i<NUMCMAPS ; i++)
- {
- sprintf(name, DEH_String("CWILV%2.2d"), i);
+ {
+ DEH_snprintf(name, 9, "CWILV%2.2d", i);
callback(name, &lnames[i]);
- }
+ }
}
else
{
for (i=0 ; i<NUMMAPS ; i++)
{
- sprintf(name, DEH_String("WILV%d%d"), wbs->epsd, i);
+ DEH_snprintf(name, 9, "WILV%d%d", wbs->epsd, i);
callback(name, &lnames[i]);
}
@@ -1593,7 +1593,7 @@ static void WI_loadUnloadData(load_callback_t callback)
// splat
callback(DEH_String("WISPLAT"), &splat[0]);
-
+
if (wbs->epsd < 3)
{
for (j=0;j<NUMANIMS[wbs->epsd];j++)
@@ -1602,17 +1602,16 @@ static void WI_loadUnloadData(load_callback_t callback)
for (i=0;i<a->nanims;i++)
{
// MONDO HACK!
- if (wbs->epsd != 1 || j != 8)
+ if (wbs->epsd != 1 || j != 8)
{
// animations
- sprintf(name, DEH_String("WIA%d%.2d%.2d"),
- wbs->epsd, j, i);
+ 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];
+ a->p[i] = anims[1][4].p[i];
}
}
}
@@ -1625,7 +1624,7 @@ static void WI_loadUnloadData(load_callback_t callback)
for (i=0;i<10;i++)
{
// numbers 0-9
- sprintf(name, DEH_String("WINUM%d"), i);
+ DEH_snprintf(name, 9, "WINUM%d", i);
callback(name, &num[i]);
}
@@ -1666,13 +1665,13 @@ static void WI_loadUnloadData(load_callback_t callback)
callback(DEH_String("WICOLON"), &colon);
// "time"
- callback(DEH_String("WITIME"), &timepatch);
+ callback(DEH_String("WITIME"), &timepatch);
// "sucks"
- callback(DEH_String("WISUCKS"), &sucks);
+ callback(DEH_String("WISUCKS"), &sucks);
// "par"
- callback(DEH_String("WIPAR"), &par);
+ callback(DEH_String("WIPAR"), &par);
// "killers" (vertical)
callback(DEH_String("WIKILRS"), &killers);
@@ -1681,16 +1680,16 @@ static void WI_loadUnloadData(load_callback_t callback)
callback(DEH_String("WIVCTMS"), &victims);
// "total"
- callback(DEH_String("WIMSTT"), &total);
+ callback(DEH_String("WIMSTT"), &total);
for (i=0 ; i<MAXPLAYERS ; i++)
{
// "1,2,3,4"
- sprintf(name, DEH_String("STPB%d"), i);
+ DEH_snprintf(name, 9, "STPB%d", i);
callback(name, &p[i]);
// "1,2,3,4"
- sprintf(name, DEH_String("WIBP%d"), i+1);
+ DEH_snprintf(name, 9, "WIBP%d", i+1);
callback(name, &bp[i]);
}
@@ -1698,19 +1697,21 @@ static void WI_loadUnloadData(load_callback_t callback)
if (gamemode == commercial)
{
- strcpy(name, DEH_String("INTERPIC"));
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
}
else if (gamemode == retail && wbs->epsd == 3)
{
- strcpy(name, DEH_String("INTERPIC"));
+ strncpy(name, DEH_String("INTERPIC"), 9);
+ name[8] = '\0';
}
- else
+ else
{
- sprintf(name, DEH_String("WIMAP%d"), wbs->epsd);
+ DEH_snprintf(name, 9, "WIMAP%d", wbs->epsd);
}
-
+
// Draw backdrop and save to a temporary buffer
-
+
callback(name, &background);
}
@@ -1723,7 +1724,7 @@ void WI_loadData(void)
{
if (gamemode == commercial)
{
- NUMCMAPS = 32;
+ NUMCMAPS = 32;
lnames = (patch_t **) Z_Malloc(sizeof(patch_t*) * NUMCMAPS,
PU_STATIC, NULL);
}
diff --git a/src/w_main.c b/src/w_main.c
new file mode 100644
index 00000000..92a394dd
--- /dev/null
+++ b/src/w_main.c
@@ -0,0 +1,206 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2010 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:
+// Common code to parse command line, identifying WAD files to load.
+//
+//-----------------------------------------------------------------------------
+
+#include "doomfeatures.h"
+#include "d_iwad.h"
+#include "m_argv.h"
+#include "w_main.h"
+#include "w_merge.h"
+#include "w_wad.h"
+#include "z_zone.h"
+
+// Parse the command line, merging WAD files that are sppecified.
+// Returns true if at least one file was added.
+
+boolean W_ParseCommandLine(void)
+{
+ boolean modifiedgame = false;
+ int p;
+
+#ifdef FEATURE_WAD_MERGE
+
+ // Merged PWADs are loaded first, because they are supposed to be
+ // modified IWADs.
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Simulates the behavior of deutex's -merge option, merging a PWAD
+ // into the main IWAD. Multiple files may be specified.
+ //
+
+ p = M_CheckParm("-merge");
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" merging %s\n", filename);
+ W_MergeFile(filename);
+ }
+ }
+
+ // NWT-style merging:
+
+ // NWT's -merge option:
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Simulates the behavior of NWT's -merge option. Multiple files
+ // may be specified.
+
+ p = M_CheckParm("-nwtmerge");
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" performing NWT-style merge of %s\n", filename);
+ W_NWTDashMerge(filename);
+ }
+ }
+
+ // Add flats
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Simulates the behavior of NWT's -af option, merging flats into
+ // the main IWAD directory. Multiple files may be specified.
+ //
+
+ p = M_CheckParm("-af");
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" merging flats from %s\n", filename);
+ W_NWTMergeFile(filename, W_NWT_MERGE_FLATS);
+ }
+ }
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Simulates the behavior of NWT's -as option, merging sprites
+ // into the main IWAD directory. Multiple files may be specified.
+ //
+
+ p = M_CheckParm("-as");
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" merging sprites from %s\n", filename);
+ W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES);
+ }
+ }
+
+ //!
+ // @arg <files>
+ // @category mod
+ //
+ // Equivalent to "-af <files> -as <files>".
+ //
+
+ p = M_CheckParm("-aa");
+
+ if (p > 0)
+ {
+ for (p = p + 1; p<myargc && myargv[p][0] != '-'; ++p)
+ {
+ char *filename;
+
+ modifiedgame = true;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" merging sprites and flats from %s\n", filename);
+ W_NWTMergeFile(filename, W_NWT_MERGE_SPRITES | W_NWT_MERGE_FLATS);
+ }
+ }
+
+#endif
+
+ //!
+ // @arg <files>
+ // @vanilla
+ //
+ // Load the specified PWAD files.
+ //
+
+ p = M_CheckParm ("-file");
+ if (p)
+ {
+ // the parms after p are wadfile/lump names,
+ // until end of parms or another - preceded parm
+ modifiedgame = true; // homebrew levels
+ while (++p != myargc && myargv[p][0] != '-')
+ {
+ char *filename;
+
+ filename = D_TryFindWADByName(myargv[p]);
+
+ printf(" adding %s\n", filename);
+ W_AddFile(filename);
+ }
+ }
+
+// W_PrintDirectory();
+
+ return modifiedgame;
+}
+
diff --git a/src/w_main.h b/src/w_main.h
new file mode 100644
index 00000000..73047b16
--- /dev/null
+++ b/src/w_main.h
@@ -0,0 +1,32 @@
+// 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.
+//
+// DESCRIPTION:
+// Common code to parse command line, identifying WAD files to load.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef W_MAIN_H
+#define W_MAIN_H
+
+boolean W_ParseCommandLine(void);
+
+#endif /* #ifndef W_MAIN_H */
+
diff --git a/src/z_zone.c b/src/z_zone.c
index a3900f5b..c7425290 100644
--- a/src/z_zone.c
+++ b/src/z_zone.c
@@ -41,6 +41,7 @@
// because it will get overwritten automatically if needed.
//
+#define MEM_ALIGN sizeof(void *)
#define ZONEID 0x1d4a11
typedef struct memblock_s
@@ -201,7 +202,7 @@ Z_Malloc
memblock_t* base;
void *result;
- size = (size + 3) & ~3;
+ size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
// scan through the block list,
// looking for the first free block