Merge from raven-branch.

Subversion-branch: /branches/strife-branch
Subversion-revision: 2051
This commit is contained in:
Simon Howard 2010-09-09 23:13:06 +00:00
commit 120d90c67b
149 changed files with 13155 additions and 1725 deletions

19
.gitignore vendored
View file

@ -1,24 +1,21 @@
CMDLINE
INSTALL
Makefile
Makefile.in
TAGS
aclocal.m4
autom4te.cache
Makefile
INSTALL
CMDLINE
autotools
bin
config.h
aclocal.m4
configure
config.hin
config.log
config.status
configure
lib
obj
config.h
autom4te.cache
rpm.spec
stamp-h
stamp-h.in
stamp-h1
tags
TAGS
# These are the default patterns globally ignored by Subversion:
*.o

View file

@ -16,8 +16,9 @@ set tags+=tags
let tagfiles = findfile("tags", ".;", -1)
" Add tag files for libraries:
call add(tagfiles, topdir . "textscreen/tags")
call add(tagfiles, topdir . "opl/tags")
call add(tagfiles, topdir . "pcsound/tags")
call add(tagfiles, topdir . "textscreen/tags")
for tagfile in tagfiles
" Don't go beyond the project top level when adding parent dirs:

15
BUGS
View file

@ -6,21 +6,6 @@
effects are cut off at the wrong distance. This needs further
investigation.
* Music plays back differently.
Vanilla Doom was typically played with a SoundBlaster (or compatible)
card. It programmed the registers for the OPL music chip directly
in order to emulate the various General MIDI instruments. However,
Chocolate Doom uses the OS's native MIDI playback interfaces to play
MIDI sound. As the OPL is programmed differently, the music sounds
different to the original, even when using an original SoundBlaster
card.
This can be worked around in the future: OPL emulation code exists that
simulates an OPL chip in software. Furthermore, depending on the OS,
it may be possible to program the OPL directly in order to get the
same sound.
* A small number of Doom bugs are almost impossible to emulate.
An example of this can be seen in Ledmeister's "Blackbug" demo which

887
ChangeLog
View file

@ -1,3 +1,890 @@
2010-05-30 04:03:44 fraggle
Add INSTALL to all distribution packages, add note in README.
2010-05-30 03:56:58 fraggle
Clarify/update install instructions.
2010-05-14 19:42:32 fraggle
Don't grab the mouse when the demo sequence advances.
2010-05-03 17:47:25 fraggle
Oops.
2010-05-03 16:58:52 fraggle
Update NEWS.
2010-05-01 22:47:26 fraggle
Further sanity checking on use of strcpy() with dehacked string
replacements.
2010-05-01 22:20:30 fraggle
Silence printf(DEH_String(...)) warnings, by providing a DEH_printf
function that checks the format string is a valid replacement. Also
add DEH_fprintf and DEH_snprintf functions to use throughout the code
to do similar checking.
2010-05-01 20:22:52 fraggle
Fix compiler warnings with savegame and response file code.
2010-04-30 20:58:30 fraggle
Merge contents of OPL-TODO into TODO file.
2010-04-30 20:38:24 fraggle
Add textscreen Doxyfile to dist. Add .desktop file to svn:ignore. Add
opl ctags file to localvimrc.
2010-04-25 00:53:03 fraggle
Add -reject_pad_with_ff parameter to allow padding value to be
specified.
2010-04-23 21:46:29 fraggle
Add REJECT buffer overflow emulation, based on code from PrBoom+
(thanks entryway). Fixes YDFEAR25.LMP.
2010-04-22 22:38:51 fraggle
Disable OPL debugging messages.
2010-03-08 18:52:59 fraggle
Add OPL-TODO to dist, set svn:ignore properties.
2010-03-08 18:50:29 fraggle
Use native MIDI music by default.
2010-03-08 01:14:23 fraggle
Merge opl-branch to trunk.
OPL support still isn't perfect, and it certainly isn't complete.
However, for now, it's good enough.
2010-02-10 20:21:21 fraggle
Bump version number, update ChangeLog and NEWS.
2010-01-31 18:21:50 fraggle
Change Windows resource file to use PACKAGE_COPYRIGHT and
PACKAGE_LICENSE macros.
2010-01-30 16:14:04 fraggle
Change directory to home directory before launching the game, so that
recorded demos go somewhere sensible.
2010-01-30 16:04:24 fraggle
Set launch button as default button, so that it is possible to launch
the game by pressing return.
2010-01-30 00:37:17 fraggle
Rename mus2mid functions to be consistent with coding standard.
2010-01-29 23:28:35 fraggle
Remove unused PACKAGE_LONGDESC.
2010-01-29 19:17:56 fraggle
When doing a MUS to MID conversion, allocate MIDI channels so that the
lowest-numbered MIDI channels are used before higher-numbered ones.
Fixes ear-piercing whistle sound in the MAP05 music when playing with
timidity and EAWPATS (thanks entryway / HackNeyed).
2010-01-29 03:55:20 fraggle
Fix indentation/style etc. in mus2mid.c.
2010-01-27 19:16:26 fraggle
Add tags files to svn:ignore properties.
2010-01-26 19:21:18 fraggle
Minor fix of British spelling -> American.
2010-01-26 19:18:18 fraggle
Fix glass hack windows where a linedef is flagged as two sided but has
only one side. Fixes WADs such as OTTAWAU.WAD (thanks Never_Again).
2010-01-23 23:06:45 fraggle
Add menu item to launcher to open a terminal window that can be used
to start the game. Add missing 'edit' menu. Set svn:ignore property
for osx directory.
2010-01-18 19:40:50 fraggle
Fix package source URL.
2010-01-18 19:29:48 fraggle
Tweak package description slightly.
2010-01-18 19:14:54 fraggle
Define project short description, copyright, maintainer and URL in
configure.in. Use these for the Info-gnustep.plist file. Add
generated .spec file for building RPM packages.
2010-01-17 16:58:37 fraggle
Update NEWS.
2010-01-17 16:31:03 fraggle
Restore the original cursor when shutting down video code, this should
hopefully fix the problem with the mouse cursor disappearing when
exiting on Win9x (thanks Janizdreg).
2010-01-16 19:20:11 fraggle
Update TODO file.
2010-01-15 19:29:28 fraggle
Don't open the configuration window when the launcher is first run;
display an error message if the user tries to launch the game without
an IWAD selected.
2010-01-15 19:14:02 fraggle
Fix GNUstep info panel.
2010-01-15 18:51:35 fraggle
Center the launcher window and config window on startup.
2010-01-15 18:40:37 fraggle
Add wadfile.png for GNUstep build.
2010-01-15 18:13:05 fraggle
Extend osx makefile to allow building of a working GNUstep
application, for testing purposes. Add GNUstep version of Info.plist,
remove app-skeleton directory and move contents up.
2010-01-14 18:47:03 fraggle
In Chex Quest, use the radiation suit colormap instead of the red
colormaps that are usually used when taking damage (or using the
berserk pack). This matches the Vanilla chex.exe behavior (thanks
Fuzztooth).
2010-01-12 20:16:25 fraggle
Oops.
2010-01-12 20:15:34 fraggle
Strip executables when building Windows CE packages.
2010-01-12 20:14:11 fraggle
Rearrange order of Makefile generation to alphabetical order.
2010-01-12 20:12:56 fraggle
Move Makefile definitions for CC and STRIP into config.make, use
versions from autoconf.
2010-01-12 20:09:54 fraggle
Set main menu title based on package name, not fixed string.
2010-01-12 20:09:01 fraggle
Place commercial level name strings consecutively in the same array,
so that overflowing the end of one list accesses the start of the
next. This trick is used by pl2.wad for its MAP33 secret level.
2010-01-12 01:32:24 fraggle
Add missing connection for plutonia.wad set button.
2010-01-12 01:20:48 fraggle
Add document icon file and use for file associations.
2010-01-11 19:10:42 fraggle
Insert new files into the command line at the correct location,
allowing multiple files to be opened at once.
2010-01-11 01:35:04 fraggle
When launching a file from the finder, add the new file into the
command line at the appropriate position in the command line string.
2010-01-10 20:46:15 fraggle
Change "@executable_path@" to "@executable_path"
2010-01-10 18:48:21 fraggle
Install docs with a single cp, rather than using a for loop.
2010-01-10 18:42:35 fraggle
Recursively copy library dependencies into destination package.
Identify libraries to be installed based on the path in which they are
located, rather than whether there is "libSDL" in the name. Use
install_name_tool to change the search path so that the system looks
for libraries in @executable_path@ rather than their location on the
machine upon which the program was built.
2010-01-09 21:06:31 fraggle
Clear existing arguments when adding a file.
2010-01-09 20:42:30 fraggle
Add file to command line when opened; add link from AppController to
LauncherManager.
2010-01-09 18:54:04 fraggle
Initial code to identify file type by extension and add file to
command line.
2010-01-09 18:38:48 fraggle
Hook in AppController as delegate for application, add file
associations to property list file.
2010-01-05 17:20:58 fraggle
Add "clean" target to package makefiles.
2010-01-05 15:52:12 fraggle
Move config.make up to pkg/ directory. Use static makefiles to
generate all packages, rather than dynamically generated makefiles.
Add pkg/osx to dist. Make OS X staging directory depend on top level
documentation files. Generate CMDLINE as part of standard build if it
is not already present. Set svn:ignore properties.
2010-01-04 22:53:44 fraggle
Fix single space error when listing libraries.
2010-01-04 22:45:45 fraggle
Copy binaries into app dir along with libraries.
2010-01-04 22:24:48 fraggle
Include documentation files in package.
2010-01-04 22:19:53 fraggle
Fix GNUstep build.
2010-01-04 22:11:11 fraggle
Generate Info.plist and config.make in configure and remove temporary
versions. Include config.h from top level.
2010-01-04 22:01:32 fraggle
Import OS X launcher code to trunk.
2010-01-03 03:49:11 fraggle
Add quotes around $@ in autogen script (thanks exp[x])
2009-12-28 20:57:20 fraggle
When recording low resolution (non-longtics) Vanilla demos, carry
forward the error from angleturn caused by the reduced resolution, so
that consecutive errors can accumulate, possibly making turning
slightly smoother.
2009-12-27 01:42:13 fraggle
Oops.
2009-12-27 00:11:18 fraggle
Allow DOOMWADDIR/DOOMWADPATH to contain the complete path to IWAD
files, as well as directories in which to search for IWAD files.
2009-12-18 22:11:06 fraggle
Fix poor quality application icons seen when the game is running. Add
back 8-bit icon files alongside files including both 8-bit and high
quality 32-bit versions. Use the high quality icon files for resource
files includes, and the low quality ones for in-game SDL.
2009-12-18 21:11:32 fraggle
Update generated source files containing icon data.
2009-12-18 21:10:35 fraggle
Make ExecuteCommand() under Unix return a failure when the executable
cannot be executed.
2009-12-14 20:57:04 fraggle
Use GetModuleFileNameW to get the (Unicode) path to the Doom
executable. This hopefully fixes problems with Unicode directory
names.
2009-12-14 18:54:25 fraggle
Add Chocolate Doom/setup icons with scaled versions for various
different icon sizes (thanks MikeRS).
2009-12-12 01:20:49 fraggle
Fix textscreen black border bug.
2009-12-09 02:40:39 fraggle
Fix the setup tool on Windows Vista/7 to not prompt for elevated
permissions and to disable the "Program Compatibility Assistant"
(thanks hobbs and MikeRS).
2009-11-29 22:50:17 fraggle
Add other missing files to dist.
2009-11-29 22:25:51 fraggle
Include .lvimrc in dist.
2009-11-21 03:56:59 fraggle
Add Makefile to build Win32 packages.
2009-11-21 02:05:56 fraggle
Use execvp() rather than execv(), to look up Doom binary in the PATH
if necessary.
2009-11-21 00:40:58 fraggle
Apply configuration file invalid key setting fix to setup code.
2009-11-21 00:38:16 fraggle
Don't crash if key settings are set in a configuration file that are
out of range (thanks entryway).
2009-11-21 00:24:59 fraggle
Fix crash with chocolate-setup under Windows (thanks Janizdreg).
2009-11-19 21:49:13 fraggle
Rework the OS X MIDI disabling code, as SDL_mixer 1.2.11 fixes the
crash. Check and disable MIDI by default if using an older version of
SDL on OS X.
2009-11-19 21:07:31 fraggle
Make chocolate-setup use its own location in the filesystem to find
the location of the chocolate-doom executable. Remove INSTALL_DIR
define.
2009-11-05 19:57:55 fraggle
Perform bounds checking on values passed to TXT_UpdateScreenArea() to
avoid crashes.
2009-10-26 19:28:12 fraggle
Initial hacks for compiling under SDL 1.3.
2009-10-17 21:13:54 fraggle
Fix error in last change.
2009-10-17 20:39:37 fraggle
Use M_StrToInt() when processing values passed with -spechit, so that
hex values can be specified.
2009-10-17 20:29:46 fraggle
Import donut overrun emulation code from PrBoom+ (Thanks entryway).
2009-10-16 19:10:30 fraggle
Fix compilation under MSVC (thanks entryway).
2009-10-10 23:58:25 fraggle
Rename pkg/wince/Makefile to pkg/wince/GNUmakefile (it uses GNU
extensions).
2009-10-10 22:46:14 fraggle
Add pkg directory to make dist.
2009-10-10 02:02:58 fraggle
Don't crash when using the donut special type and the joining linedef
is one sided (thanks Alexander Waldmann).
2009-10-05 21:25:53 fraggle
Fix desync in ep1-0500.lmp on 64-bit (thanks exp(x)).
2009-10-05 00:38:14 fraggle
Provide pointer to STARTUPINFO structure when calling CreateProcessW,
to stop crash under normal Windows (not CE) when launching Doom from
the setup tools (thanks Janizdreg).
2009-10-01 20:08:21 fraggle
Oops.
2009-10-01 02:04:00 fraggle
Oops.
2009-10-01 00:07:03 fraggle
Change British English spellings to American English, for consistency.
2009-09-20 16:27:40 fraggle
Use "const char" in libtextscreen where appropriate (thanks entryway).
2009-09-11 22:56:47 fraggle
Add (lack of) copyright notice for SDL workaround.
2009-09-07 20:43:04 fraggle
Fix compilation under MacOS X.
2009-09-06 19:15:52 fraggle
Fixes for MSVC compile (thanks entryway).
2009-08-28 00:27:47 fraggle
Allow PGUP/PGDN to scroll up and down in scroll panes (thanks
LionsPhil).
2009-07-20 23:27:59 fraggle
Remove redundant variable assignment (thanks Quasar/Yagisan)
2009-07-20 01:37:41 fraggle
Save and display the loading disk icon as a fixed 16x16 square, from
an image drawn at the bottom right corner of the screen. This seems
to be the same as how Vanilla behaves, and fixes chook3.wad, that uses
an STDISK replacement with an offset that pushes the image to the
left.
2009-07-13 23:43:06 fraggle
Add stdio.h include to fix MSVC build (thanks Kaiser)
2009-07-12 17:47:12 fraggle
Fix compile with libsamplerate.
2009-07-12 15:00:50 fraggle
On Windows CE, use the Windows API to find the amount of available
memory, so that at least two megabytes are always left available to
the OS.
2009-07-11 12:15:32 fraggle
Add missing item to NEWS.
2009-07-07 20:46:55 fraggle
Update NEWS.
2009-07-07 20:38:00 fraggle
Fix launching of the game from the setup tool in Windows CE.
2009-06-21 20:33:35 fraggle
Add Makefile for building CAB files, dependency calculation.
2009-06-21 20:19:43 fraggle
Use correct filename for SDL_net DLL.
2009-06-21 20:03:38 fraggle
Remove temporary files after generating CAB file.
2009-06-20 23:13:44 fraggle
Add script to generate Windows CE install package.
2009-06-16 20:47:13 fraggle
Automatically allocate a smaller zone size if it was not possible to
allocate the default 16 MiB.
2009-06-13 18:10:18 fraggle
Don't post zero key events.
2009-06-12 20:07:55 fraggle
On Windows CE systems without a keyboard, patch the default settings
to use hardware keys.
2009-06-12 18:58:42 fraggle
Remove debug messages.
2009-06-12 18:35:39 fraggle
Set the USER environment variable based on the owner information from
the registry.
2009-06-12 18:34:27 fraggle
Always grab input on Windows CE.
2009-06-11 22:34:36 fraggle
Include libc_wince.a in chocolate-server build.
2009-06-11 20:41:20 fraggle
Grab the input in setup when reading a new key binding, so that
Windows CE buttons are read properly. Map buttons to PC function
keys.
2009-06-11 19:19:05 fraggle
Include libc_wince.h on Windows CE.
2009-06-11 19:18:12 fraggle
Declare getenv/putenv on Windows CE for recent SDL versions that do
not declare it.
2009-06-10 20:03:08 fraggle
Add key bindings for pause, message refresh.
2009-06-08 20:26:29 fraggle
Remove debugging code.
2009-06-08 19:15:57 fraggle
Use SDL's getenv/putenv implementation, and populate at startup.
2009-06-08 00:41:10 fraggle
Use CreateFileW instead of OpenFile (doesn't exist on Windows CE)
2009-06-07 20:08:08 fraggle
Fix header includes (thanks exp[x])
2009-06-07 19:18:02 fraggle
Don't add DirectX/Windib selector on Windows CE.
2009-06-07 18:53:25 fraggle
Use home dir to store configuration and savegames under Windows CE.
2009-06-07 18:33:19 fraggle
Fix setup tool display configuration dialog when fullscreen is not
supported.
2009-06-07 18:10:05 fraggle
Make auto-adjust code switch to windowed mode if no fullscreen modes
are available.
2009-06-07 17:41:46 fraggle
Catch errors when initialising SDL. Use the small textscreen font by
default on Windows CE if no fullscreen modes are available.
2009-06-07 17:39:08 fraggle
Add missing SDL_thread include.
2009-06-07 17:35:43 fraggle
Don't try to use the SDL DirectX driver under Windows CE.
2009-06-07 16:21:41 fraggle
Fix setup tool compile on Windows CE.
2009-06-07 16:15:40 fraggle
Remove call to setbuf.
2009-06-07 15:35:27 fraggle
Add IWAD search dirs for Windows CE.
2009-06-07 15:20:46 fraggle
Exit with an error on failure to allocate zone memory.
2009-06-07 03:10:21 fraggle
Use MessageBoxW instead of MessageBox (doesn't exist on Windows CE)
2009-06-07 02:59:49 fraggle
Add README file for Windows CE library.
2009-06-07 02:56:21 fraggle
Detect Windows CE target and build/include libc_wince files as
necessary.
2009-06-07 02:50:47 rtc_marine
- Update textscreen codeblocks project to include txt_scrollpane.* and
txt_smallfont.h
2009-06-07 02:33:58 fraggle
Include libc_wince.h when on Windows CE.
2009-06-07 02:32:15 fraggle
Add CPU affinity function for Windows CE.
2009-06-07 02:27:58 fraggle
Add libc_wince.h header, and EISDIR error value.
2009-06-07 02:27:30 fraggle
Use GetUserNameExW, not GetUserName (doesn't exist on WinCE)
2009-06-07 02:26:45 fraggle
Fix compile with FEATURE_MULTIPLAYER disabled.
2009-06-07 02:24:40 fraggle
Fix compile with FEATURE_SOUND disabled.
2009-06-07 01:56:23 fraggle
Add Windows CE implementations of some ANSI C functions that are
missing.
2009-06-06 22:13:44 fraggle
Don't check for Steam/CD installer versions on Windows CE.
2009-06-05 17:58:48 fraggle
Add key binding variables for automap and weapon keys.
2009-06-04 00:37:02 fraggle
Increase height of menu bindings dialog.
2009-06-04 00:35:05 fraggle
Use newer keyboard bindings dialog layout from raven-branch.
2009-06-04 00:20:37 fraggle
Add unique key groups for menu navigation and shortcuts.
2009-06-04 00:20:06 fraggle
Use key for confirming menu messages, not typed char.
2009-06-03 21:45:54 fraggle
Add dialog to setup tool for editing menu shortcuts.
2009-06-03 21:18:04 fraggle
Add config file variables to increase/decrease screen size.
2009-06-03 20:59:26 fraggle
Fix shortcut keys for menu items.
2009-06-03 20:55:50 fraggle
Add configuration file entries for menu key bindings.
2009-06-03 20:37:19 fraggle
Add key_ variables for the keys used to control the menu.
2009-05-26 23:14:24 fraggle
Fix tags for functions using TXT_UNCAST_ARG.
2009-05-26 22:13:18 fraggle
Set appropriate vim 'tags' variable for ctags files.
2009-05-21 20:18:38 fraggle
Set display settings window position based on screen dimensions,
rather than hard coding position.
2009-05-19 18:07:49 fraggle
Fix manpage documentation for DOOMWADPATH (thanks MikeRS)
2009-05-18 19:30:49 fraggle
Fix A_BossDeath behavior in v1.9 emulation mode (thanks entryway)
2009-05-17 14:54:19 fraggle
Always use an SDL buffer size that is a power of two. Reduce buffer
size to 70ms.
2009-05-12 19:03:20 fraggle
Add option to "join game" dialog in setup tool to autojoin a LAN game.
2009-05-12 19:01:27 fraggle
Make txt_inputboxes emit a "changed" signal when their value is
changed.
2009-05-07 22:59:38 fraggle
Calculate SDL buffer size automatically based on sample rate.
2009-05-05 01:00:53 fraggle
Better ASCII chart.
2009-05-05 00:46:27 fraggle
Minor smallfont fixups.
2009-05-01 22:05:57 fraggle
Add copyright headers to textscreen examples.
2009-04-26 17:59:08 fraggle
More smallfont fixups.
2009-04-23 20:58:11 fraggle
Fix up some extended ASCII characters.
2009-04-23 19:19:52 fraggle
Oops.
2009-04-23 19:18:43 fraggle
Add small textscreen font for low resolution displays, based on the
Atari-Small font by Tom Fine.
2009-03-15 14:44:23 fraggle
Fix clipped sounds when using libsamplerate (thanks David Flater)
2009-03-14 15:28:41 fraggle
Add check to allow sched_setaffinity code to work on older versions of
libc.
2009-03-12 18:55:27 fraggle
Define INVALID_SET_FILE_POINTER if it is not defined, to fix
compilation under MSVC6 (thanks Quasar)
2009-03-08 22:51:25 fraggle
Add "make doc" target to run Doxygen, and add a Doxyfile. Add @file
tags to start of header files so that Doxygen will process them.
2009-03-07 00:35:08 fraggle
Add documentation for high-level txt_desktop.h functions.
2009-03-07 00:24:45 fraggle
Add documentation for high-level textscreen functions.
2009-03-06 20:01:32 fraggle
Fix signed/unsigned conversion warning.
2009-03-03 19:26:20 fraggle
Look up SetProcessAffinityMask function at runtime, so that the
program should work under Win9x again.
2009-01-30 23:53:47 fraggle
Fix layout of widgets within scroll panes. Scroll scroll panes in
response to keyboard events.
2009-01-29 23:26:03 fraggle
Shrink text box slightly.
2009-01-29 23:00:14 fraggle
Allow clicking within scroll bars to set position.
2009-01-29 22:54:13 fraggle
Add scrollable pane widget to textscreen library.
2009-01-17 14:05:31 fraggle
Fix '-mmap' command line parameter.
2009-01-07 22:05:13 fraggle
Create the ~/.chocolate-doom/savegames directory on startup if it does
not exist.
2009-01-07 21:51:37 fraggle
Replace -nommap with -mmap; do not use mmap()ed file access by
default. Fixes Plutonia 2, and several other minor things.
2008-12-10 20:25:05 fraggle
Bump version to 1.2.1, update NEWS and ChangeLog.
2008-12-10 20:20:10 fraggle
Fix crash when playing Doom 1 levels.

159
INSTALL
View file

@ -2,13 +2,18 @@
Chocolate Doom installation
===========================
These are instructions for how to install Chocolate Doom on Unix-like
Operating Systems.
These are instructions for how to install and set up Chocolate Doom
for play.
Dependencies
------------
Building Chocolate Doom
-----------------------
Chocolate Doom requires the following to be installed:
Before you can play Chocolate Doom, you need to compile a binary that
you can run. If you are using Windows or Mac OS X, precompiled
binaries are available on the website for download, and you can skip
this section.
For compilation, Chocolate Doom requires the following to be installed:
* A C compiler (gcc is recommended)
* make (GNU make is recommended)
@ -17,84 +22,108 @@ Chocolate Doom requires the following to be installed:
* SDL_net (see http://www.libsdl.org/projects/SDL_net/)
* Python (optional)
Building Chocolate Doom
-----------------------
On a Unix system, follow the standard instructions for installing an
autotools-based package:
Follow the standard instructions for installing an autotools-based
package:
1. Run './configure' to initialize the package.
2. Run 'make' to compile the package.
3. Run 'make install' to install the package.
Advanced topics such as cross-compilation are beyond the scope of this
Advanced topics such as cross-compilation are beyond the scope of this
document. Please see the GNU autoconf / automake documentation for more
information.
Installing an IWAD file
-----------------------
Obtaining an IWAD file
----------------------
To play Doom, an IWAD file is needed. This contains the Doom game data. The
file usually has one of the following filenames:
To play Doom, you need an IWAD file. This file contains the game data
that is used in gameplay (graphics, sounds, etc). The full versions of
the Doom games are proprietary and need to be bought. The IWAD file
has one of the following names:
doom1.wad (Shareware Doom)
doom.wad (Registered / Ultimate Doom)
doom2.wad (Doom 2)
tnt.wad (Final Doom: TNT: Evilution)
plutonia.wad (Final Doom: Plutonia Experiment)
chex.wad (Chex Quest)
When you have this file (see the next section, "Obtaining an IWAD file", for
how to get this file), install it through one of the following methods:
If you don't have a copy of the commercial version, you can download
the shareware version (extract the file named doom1.wad):
* Put the file into the /usr/share/games/doom or
/usr/local/share/games/doom directories.
* Install it into a directory and set the environment variable DOOMWADDIR to
be the path to that directory.
* Install multiple IWADs into separate directories and set the environment
variable DOOMWADPATH to be a colon-separated list of directories to search
(similar to the Unix PATH environment variable).
* Run Chocolate Doom with the '-iwad' command line parameter to specify the
IWAD file to use, eg.
* http://www.doomworld.com/idgames/index.php?id=7053
(idstuff/doom/win95/doom95.zip in your nearest /idgames mirror)
chocolate-doom -iwad /root/doom2.wad
If you have a commercial version, obtaining the IWAD file may slightly
complicated. The method depends on how you obtained your copy of the
game:
Obtaining an IWAD file
----------------------
* There have been several CD-based versions of Doom. Generally, the
IWAD files can be found on the CD and copied off directly.
Obtaining the IWAD file may be a complicated process under Unix. The method
depends on how you obtained your copy of the game:
* The IWAD files might not be directly available on the CD. Look for
a program named "deice.exe". In the same directory, there should
be a single large file with a numbered extension (eg.
"resource.1"); to extract this, follow the same instructions as for
the floppy disk version (see below).
* There have been several CD-based versions of Doom. Generally, the IWAD
files can be found on the CD and copied off directly.
* If you have the floppy disk version of Doom, first copy the
contents of all the floppy disks into a directory together. You
will have several large files with numbered extensions.
Concatenate these into a single file, eg.
* The IWAD files may not be directly available on the CD. Look for a program
named "deice.exe". In the same directory, there should be a single large
file with a numbered extension (eg. "resource.1"); to extract this, follow
the same instructions as for the floppy disk version (see below).
(Unix instructions)
cat doom_se.1 doom_se.2 doom_se.3 doom_se.4 doom_se.5 > doom_se.exe
* If you have the floppy disk version of Doom, first copy the contents of all
the floppy disks into a directory together. You will have several large
files with numbered extensions. Concatenate these into a single file, eg.
(Windows/DOS instructions)
copy doom_se.1+doom_se.2+doom_se.3+doom_se.4+doom_se+5 doom_se.exe
cat doom_se.1 doom_se.2 doom_se.3 doom_se.4 doom_se.5 > doom_se.exe
The resulting file is self-extracting LHA file. If you have a DOS emulator
(such as DOSbox), you can run it to extract the files; alternatively, you
can use the Unix LHA tool to extract the archive.
The resulting file is self-extracting LHA file. If you have a DOS
emulator (such as DOSbox), you can run it to extract the files;
alternatively, you can use the Unix LHA tool to extract the
archive.
* The Doom games are also available for download on Steam
(http://www.steampowered.com/). To find the IWAD files, look in your Steam
directory, under the "steamapps/common" path.
(http://www.steampowered.com/). To find the IWAD files, look in
your Steam directory, under the "steamapps/common" path.
Running the game
----------------
When you have an IWAD file, install it through one of the following
methods:
* Under Mac OS X, you can specify the locations of the IWAD files
through the graphical launcher program. Click the "Configure..."
button, and then click "Set..." for each IWAD location to choose
its location.
* Under Unix, put the file into the /usr/share/games/doom or
/usr/local/share/games/doom directories.
* Place it in a directory and set the environment variable DOOMWADDIR
to be the path to that directory.
* Install multiple IWADs into separate directories and set the
environment variable DOOMWADPATH to be a colon-separated list of
directories to search (similar to the Unix PATH environment
variable).
* Run Chocolate Doom with the '-iwad' command line parameter to
specify the IWAD file to use, eg.
chocolate-doom -iwad /root/doom2.wad
Playing with Chex Quest
-----------------------
Chex Quest is a game based on Doom with some minor modifications that was
distributed with boxes of Chex cereal in 1997. It is possible to play
Chex Quest using Chocolate Doom. To do this, the following files are
needed:
Chex Quest is a game based on Doom with some minor modifications that
was distributed with boxes of Chex cereal in 1997. It is possible to
play Chex Quest using Chocolate Doom. To do this, the following files
are needed:
* The IWAD file 'chex.wad', from the Chex Quest CD.
* The dehacked patch 'chex.deh', which can be found in the /idgames
repository in utils/exe_edit/patches/chexdeh.zip.
@ -106,30 +135,30 @@ line parameter to specify the Chex Quest IWAD file:
Installing upgrades
-------------------
Chocolate Doom requires a Doom 1.9 IWAD file. Generally, if you install a
recent version of Doom you should automatically have a 1.9 IWAD. However, if
you are installing from a very old CD version or from floppy disks, you might
find you have an older version.
Chocolate Doom requires a Doom 1.9 IWAD file. Generally, if you
install a recent version of Doom you should automatically have a 1.9
IWAD. However, if you are installing from a very old CD version or
from floppy disks, you might find you have an older version.
The most obvious symptom of an out of date IWAD file is that the game will
exit at the title screen before the demo starts, with the message "Demo is
from a different game version!". If this happens, your IWAD file is out of
date and you need to upgrade.
The most obvious symptom of an out of date IWAD file is that the game
will exit at the title screen before the demo starts, with the message
"Demo is from a different game version!". If this happens, your IWAD
file is out of date and you need to upgrade.
Id Software released upgrade patches that will update your game to 1.9. The
following sites have the patches:
Id Software released upgrade patches that will update your game to
1.9. The following sites have the patches:
http://www.doomworld.com/files/patches.shtml
http://www.doomworld.com/files/patches.shtml
http://www.doom2.net/doom2/utils.html
ftp://ftp.idsoftware.com/idstuff/doom2
As the patches are binary patches that run as DOS executables, you will
need a DOS emulator (such as DOSBox) to install them.
As the patches are binary patches that run as DOS executables, you
will need a DOS emulator (such as DOSBox) to install them.
Music support
-------------
Support for Doom's MIDI music is available through timidity:
Support for Doom's MIDI music is available through Timidity:
http://timidity.sourceforge.net/

View file

@ -50,6 +50,7 @@ EXTRA_DIST= \
config.h \
CMDLINE \
HACKING \
README.OPL \
TODO \
BUGS \
rpm.spec
@ -57,7 +58,9 @@ EXTRA_DIST= \
MAINTAINERCLEANFILES = $(AUX_DIST_GEN)
docdir=$(prefix)/share/doc/@PACKAGE@
SUBDIRS=wince textscreen pcsound src man
SUBDIRS=wince textscreen opl pcsound src man
DIST_SUBDIRS=pkg $(SUBDIRS)
if HAVE_PYTHON

66
NEWS
View file

@ -1,4 +1,66 @@
...
1.5.0 (2010-??-??):
Big changes in this version:
* The DOSbox OPL emulator (DBOPL) has been imported to replace
the older FMOPL code. The quality of OPL emulation is now
therefore much better.
* When running in windowed mode, it is now possible to
dynamically resize the window by dragging the window borders.
* There are now keyboard, mouse and joystick bindings to cycle
through available weapons, making play with joypads or mobile
devices (ie. without a proper keyboard) much more practical.
* There is now a key binding to change the multiplayer spy key
(usually F12).
* There is now a configuration file parameter to set the OPL I/O
port, for cards that don't use port 0x388.
* Up to 8 mouse buttons are now supported (including the
mousewheel).
Bugs fixed:
* It is now possible to use OPL emulation at 11025Hz sound
sampling rate (thanks to the new OPL emulator).
* The span renderer function (used for drawing floors and
ceilings) now behaves the same as Vanilla Doom, so screenshots
are pixel-perfect identical to Vanilla Doom (thanks Porsche
Monty).
* The zone memory system now aligns allocated memory to 8-byte
boundaries on 64-bit systems, which may fix crashes on systems
such as sparc64.
* The configure script now checks for libm, fixing compile
problems on Fedora Linux.
1.4.0 (2010-07-10):
The biggest change in this version is the addition of OPL
emulation. This emulates Vanilla Doom's MIDI playback when
using a Yamaha OPL synthesizer chip, as was found on
SoundBlaster compatible cards.
A software OPL emulator is included as most modern computers do
not have a hardware OPL chip any more. If you do have one, you
can configure Chocolate Doom to use it; see README.OPL.
The OPL playback feature is not yet perfect or 100% complete,
but is judged to be good enough for general use. If you find
music that does not play back properly, please report it as a
bug.
Other changes:
* The REJECT overflow emulation code from PrBoom+ has been
imported. This fixes demo desync on some demos, although
others will still desync.
* Warnings are now generated for invalid dehacked replacements of
printf format strings. Some potential buffer overflows are
also checked.
* The installation instructions (INSTALL file) have been
clarified and made more platform-agnostic.
* The mouse is no longer warped to the center of the screen when
the demo sequence advances.
* Key bindings can now be changed for the demo recording quit key
(normally 'q') and the multiplayer messaging keys (normally
't', 'g', 'i', 'b' and 'r').
1.3.0 (2010-02-10):
* Chocolate Doom now runs on Windows Mobile/Windows CE!
* It is possible to rebind most/all of the keys that control the
@ -35,6 +97,8 @@
* When recording shorttics demos, errors caused by the reduced
turning resolution are carried forward, possibly making turning
smoother.
* The source tarball can now be used to build an RPM package:
rpmbuild -tb chocolate-doom-VER.tar.gz
Compatibility:
* The A_BossDeath behavior in v1.9 emulation mode was fixed

55
README
View file

@ -13,33 +13,37 @@ Chocolate Doom aims to:
* As far as possible, provide all the same features that are available
using the DOS version.
== Setting up gameplay ==
For instructions on how to set up Chocolate Doom for play, see the
INSTALL file.
== Configuration File ==
Chocolate Doom is compatible with the DOS Doom configuration file
(normally named 'default.cfg'). Existing configuration files for
DOS Doom should therefore simply work out of the box. However,
Chocolate Doom also provides some extra settings. These are stored
in a separate file named 'chocolate-doom.cfg'.
(normally named 'default.cfg'). Existing configuration files for DOS
Doom should therefore simply work out of the box. However, Chocolate
Doom also provides some extra settings. These are stored in a
separate file named 'chocolate-doom.cfg'.
The configuration can be edited using the chocolate-setup tool.
== Command-line options ==
For a complete list of command-line options, see the CMDLINE
file.
For a complete list of command-line options, see the CMDLINE file.
== Playing TCs ==
With Vanilla Doom there is no way to include sprites in PWAD files.
Chocolate Doom's '-file' command line option behaves exactly the
same as Vanilla Doom, and trying to play TCs by adding the WAD files
using '-file' will not work.
With Vanilla Doom there is no way to include sprites in PWAD files.
Chocolate Doom's '-file' command line option behaves exactly the same
as Vanilla Doom, and trying to play TCs by adding the WAD files using
'-file' will not work.
Many Total Conversions (TCs) are distributed as a PWAD file which must
be merged into the main IWAD. Typically a copy of DEUSF.EXE is
included which performs this merge. Chocolate Doom includes a new
option, '-merge', which will simulate this merge. Essentially, the
WAD directory is merged in memory, removing the need to modify the
option, '-merge', which will simulate this merge. Essentially, the
WAD directory is merged in memory, removing the need to modify the
IWAD on disk.
To play TCs using Chocolate Doom, run like this:
@ -53,26 +57,27 @@ Here are some examples:
== Other information ==
* More information, including information about how to play various classic
TCs, is available on the Chocolate Doom website:
* More information, including information about how to play various
classic TCs, is available on the Chocolate Doom website:
http://www.chocolate-doom.org/
You are encouraged to sign up and contribute any useful information you may
have regarding the port!
You are encouraged to sign up and contribute any useful information
you may have regarding the port!
* Chocolate Doom is not perfect. See the BUGS file for a list of known
issues. New bug reports can be submitted to the Chocolate Doom bug
tracker on Sourceforge. See:
* Chocolate Doom is not perfect. See the BUGS file for a list of
known issues. New bug reports can be submitted to the Chocolate
Doom bug tracker on Sourceforge. See:
http://sourceforge.net/projects/chocolate-doom
* Source code patches are welcome, but please follow the style guidelines -
see the file named HACKING included with the source distribution.
* Source code patches are welcome, but please follow the style
guidelines - see the file named HACKING included with the source
distribution.
* Chocolate Doom is distributed under the GNU GPL. See the COPYING file
for more information.
* Chocolate Doom is distributed under the GNU GPL. See the COPYING
file for more information.
* Please send any feedback, questions or suggestions to fraggle@gmail.com.
Thanks!
* Please send any feedback, questions or suggestions to
fraggle@gmail.com. Thanks!

107
README.OPL Normal file
View file

@ -0,0 +1,107 @@
== Chocolate Doom hardware OPL support notes ==
Chocolate Doom is able to play MIDI music as it sounds in Vanilla Doom
with an OPL chip (as found in the Yamaha Adlib card, the Sound Blaster
and its clones). Most modern computers do not include an OPL chip any
more, as CPUs are fast enough to do decent software MIDI synthesis.
For this reason, a software OPL emulator is included as a substitute.
However, no software emulator sounds exactly like a real (hardware)
OPL chip, so if you do have a sound card with hardware OPL, here's how
to configure Chocolate Doom to use it.
=== Sound cards with OPL chips ===
If you have an ISA sound card, it almost certainly includes an OPL
chip. Modern computers don't have slots for ISA cards though, so you
must be running a pretty old machine.
If you have a PCI sound card, you probably don't have an OPL chip.
However, there are some exceptions to this. The following cards are
known to include "legacy" OPL support:
* C-Media CMI8738 (*)
* Forte Media FM801
* Cards based on the Yamaha YMF724 (*)
Other cards that apparently have OPL support but have not been tested:
* S3 SonicVibes
* AZTech PCI 168 (AZT 3328 chipset)
* ESS Solo-1 sound cards (ES1938, ES1946, ES1969 chipset)
* Conexant Riptide Audio/Modem combo cards
* Cards based on the Crystal Semiconductors CS4281
* Cards based on the Avance Logic ALS300
* Cards based on the Avance Logic ALS4000
If you desperately want hardware OPL music, you may be able to find
one of these cards for sale cheap on eBay.
For the cards listed above with (*) next to them, OPL support is
disabled by default and must be explictly enabled in software.
If your machine is not a PC, you don't have an OPL chip, and you will
have to use the software OPL.
=== Operating System support ===
If you're certain that you have a sound card with hardware OPL, you
may need to take extra steps to configure your operating system to
allow access to it. To do hardware OPL, Chocolate Doom must access
the chip directly, which is usually not possible in modern operating
systems unless you are running as the superuser (root/Administrator).
=== Windows 9x ===
If you're running Windows 95, 98 or Me, there is no need to configure
anything. Windows allows direct access to the OPL chip. You can
confirm that hardware OPL is working by checking for this message in
stdout.txt:
OPL_Init: Using driver 'Win32'.
=== Windows NT (including 2000, XP and later) ===
If you're running an NT-based system, it is not possible to directly
access the OPL chip, even when running as Administrator. Fortunately,
it is possible to use the "ioperm.sys" driver developed for Cygwin:
http://openwince.sourceforge.net/ioperm/
It is not necessary to have Cygwin installed to use this. Copy the
ioperm.sys file into the same directory as the Chocolate Doom
executable and it should be automatically loaded.
You can confirm that hardware OPL is working by checking for this
message in stdout.txt:
OPL_Init: Using driver 'Win32'.
=== Linux ===
If you are using a system based on the Linux kernel, you can access
the OPL chip directly, but you must be running as root. You can
confirm that hardware OPL is working, by checking for this message on
startup:
OPL_Init: Using driver 'Linux'.
If you are using one of the PCI cards in the list above with a (*)
next to it, you may need to manually enable FM legacy support. Add
the following to your /etc/modprobe.conf file to do this:
options snd-ymfpci fm_port=0x388
options snd-cmipci fm_port=0x388
=== OpenBSD/NetBSD ===
You must be running as root to access the hardware OPL directly. You
can confirm that hadware OPL is working by checking for this message
on startup:
OPL_Init: Using driver 'OpenBSD'.
=== FreeBSD ===
There is no native OPL backend for FreeBSD yet. Sorry!

20
TODO
View file

@ -1,6 +1,5 @@
Currently in progress:
* OPL MIDI playback (see: opl-branch)
* Heretic/Hexen support (see: raven-branch)
* Strife support (see: strife-branch)
@ -36,3 +35,22 @@ Crazy pie in the sky ideas:
* DWANGO-like interface for finding players and setting up games.
* Video capture mode?
== OPL TODO list ==
Needs research:
* Strategy when no more voices are available is still wrong
* Scale levels don't exactly match Vanilla (off-by-one?)
Bad MIDIs:
* doom2.wad MAP01
* gothicdm MAP05
* tnt.wad MAP30
* Alien Vendetta (title screen, MAP01, etc)
Other tasks:
* Get a better software OPL emulator
* DMXOPTIONS opl3/phase option support.

View file

@ -9,19 +9,19 @@
#define PACKAGE_NAME "Chocolate Doom"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "Chocolate Doom 1.2.1"
#define PACKAGE_STRING "Chocolate Doom 1.4.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "chocolate-doom"
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.2.1"
#define PACKAGE_VERSION "1.4.0"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "1.2.1"
#define VERSION "1.4.0"
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */

View file

@ -1,21 +1,21 @@
1 ICON "../data/doom.ico"
1 VERSIONINFO
PRODUCTVERSION 1,2,1,0
FILEVERSION 1,2,1,0
PRODUCTVERSION 1,4,0,0
FILEVERSION 1,4,0,0
FILETYPE 1
{
BLOCK "StringFileInfo"
{
BLOCK "040904E4"
{
VALUE "FileVersion", "1.2.1"
VALUE "FileDescription", "1.2.1"
VALUE "FileVersion", "1.4.0"
VALUE "FileDescription", "1.4.0"
VALUE "InternalName", "Chocolate-Doom"
VALUE "CompanyName", "Chocolate-Doom"
VALUE "LegalCopyright", "GNU General Public License"
VALUE "ProductName", "Chocolate-Doom"
VALUE "ProductVersion", "1.2.1"
VALUE "ProductVersion", "1.4.0"
}
}
}

View file

@ -3,21 +3,21 @@
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "setup-manifest.xml"
1 VERSIONINFO
PRODUCTVERSION 1,2,1,0
FILEVERSION 1,2,1,0
PRODUCTVERSION 1,4,0,0
FILEVERSION 1,4,0,0
FILETYPE 1
{
BLOCK "StringFileInfo"
{
BLOCK "040904E4"
{
VALUE "FileVersion", "1.2.1"
VALUE "FileVersion", "1.4.0"
VALUE "FileDescription", "Chocolate-Doom Setup"
VALUE "InternalName", "chocolate-setup"
VALUE "CompanyName", "fraggle@gmail.com"
VALUE "LegalCopyright", "GNU General Public License"
VALUE "ProductName", "Chocolate-Doom Setup"
VALUE "ProductVersion", "1.2.1"
VALUE "ProductVersion", "1.4.0"
}
}
}

View file

@ -1,4 +1,4 @@
AC_INIT(Chocolate Doom, 1.2.1, fraggle@gmail.com, chocolate-doom)
AC_INIT(Chocolate Doom, 1.4.0, fraggle@gmail.com, chocolate-doom)
PACKAGE_SHORTDESC="Conservative Doom source port"
PACKAGE_COPYRIGHT="Copyright (C) 1993-2010"
@ -74,9 +74,16 @@ AC_SDL_MAIN_WORKAROUND([
# Check for libsamplerate.
AC_CHECK_LIB(samplerate, src_new)
AC_CHECK_LIB(m, log)
AC_CHECK_HEADERS([linux/kd.h dev/isa/spkrio.h dev/speaker/speaker.h])
AC_CHECK_FUNCS(mmap sched_setaffinity)
AC_CHECK_FUNCS(mmap sched_setaffinity ioperm)
# OpenBSD I/O i386 library for I/O port access.
# (64 bit has the same thing with a different name!)
AC_CHECK_LIB(i386, i386_iopl)
AC_CHECK_LIB(amd64, amd64_iopl)
])
AC_CHECK_TOOL(WINDRES, windres, )
@ -138,6 +145,8 @@ AC_DEFUN([AC_DATAROOTDIR_CHECKED])
AC_OUTPUT([
Makefile
man/Makefile
opl/Makefile
opl/examples/Makefile
pcsound/Makefile
pkg/Makefile
pkg/config.make

View file

@ -28,6 +28,17 @@ specifies a PC speaker driver to use for sound effect playback. Valid
options are "Linux" for the Linux console mode driver, "BSD" for the
NetBSD/OpenBSD PC speaker driver, and "SDL" for SDL-based emulated PC speaker
playback (using the digital output).
.TP
\fBOPL_DRIVER\fR
When using OPL MIDI playback, this environment variable specifies an
OPL backend driver to use. Valid options are "SDL" for an SDL-based
software emulated OPL chip, "Linux" for the Linux hardware OPL driver,
and "OpenBSD" for the OpenBSD/NetBSD hardware OPL driver.
Generally speaking, a real hardware OPL chip sounds better than software
emulation; however, modern machines do not often include one. If
present, it may still require extra work to set up and elevated
security privileges to access.
.SH FILES
.TP
\fB$HOME/.chocolate-doom/default.cfg\fR

View file

@ -11,16 +11,16 @@
#define PACKAGE_NAME "Chocolate Doom"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "Chocolate Doom 1.2.1"
#define PACKAGE_STRING "Chocolate Doom 1.4.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "chocolate-doom"
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.2.1"
#define PACKAGE_VERSION "1.4.0"
/* Version number of package */
#define VERSION "1.2.1"
#define VERSION "1.4.0"
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */

View file

@ -32,21 +32,21 @@
#endif
1 VERSIONINFO
PRODUCTVERSION 1,2,1,0
FILEVERSION 1,2,1,0
PRODUCTVERSION 1,4,0,0
FILEVERSION 1,4,0,0
FILETYPE 1
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "FileVersion", "1.2.1"
VALUE "FileDescription", "Chocolate Doom 1.2.1"
VALUE "FileVersion", "1.4.0"
VALUE "FileDescription", "Chocolate Doom 1.4.0"
VALUE "InternalName", "chocolate-doom"
VALUE "CompanyName", "fraggle@gmail.com"
VALUE "LegalCopyright", "GNU General Public License"
VALUE "ProductName", "Chocolate Doom"
VALUE "ProductVersion", "1.2.1"
VALUE "ProductVersion", "1.4.0"
END
END
END

7
opl/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile.in
Makefile
.deps
libopl.a
*.rc
tags
TAGS

19
opl/Makefile.am Normal file
View file

@ -0,0 +1,19 @@
AM_CFLAGS=@SDLMIXER_CFLAGS@
SUBDIRS = . examples
noinst_LIBRARIES=libopl.a
libopl_a_SOURCES = \
opl_internal.h \
opl.c opl.h \
opl_linux.c \
opl_obsd.c \
opl_queue.c opl_queue.h \
opl_sdl.c \
opl_timer.c opl_timer.h \
opl_win32.c \
ioperm_sys.c ioperm_sys.h \
dbopl.c dbopl.h

1602
opl/dbopl.c Normal file

File diff suppressed because it is too large Load diff

203
opl/dbopl.h Normal file
View file

@ -0,0 +1,203 @@
/*
* Copyright (C) 2002-2010 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <inttypes.h>
//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume
#define WAVE_HANDLER 10
//Use a logarithmic wavetable with an exponential table for volume
#define WAVE_TABLELOG 11
//Use a linear wavetable with a multiply table for volume
#define WAVE_TABLEMUL 12
//Select the type of wave generator routine
#define DBOPL_WAVE WAVE_TABLEMUL
typedef struct _Chip Chip;
typedef struct _Operator Operator;
typedef struct _Channel Channel;
typedef uintptr_t Bitu;
typedef intptr_t Bits;
typedef uint32_t Bit32u;
typedef int32_t Bit32s;
typedef uint16_t Bit16u;
typedef int16_t Bit16s;
typedef uint8_t Bit8u;
typedef int8_t Bit8s;
#if (DBOPL_WAVE == WAVE_HANDLER)
typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
#endif
#define DB_FASTCALL
typedef Bits (*VolumeHandler)(Operator *self);
typedef Channel* (*SynthHandler)(Channel *self, Chip* chip, Bit32u samples, Bit32s* output );
//Different synth modes that can generate blocks of data
typedef enum {
sm2AM,
sm2FM,
sm3AM,
sm3FM,
sm4Start,
sm3FMFM,
sm3AMFM,
sm3FMAM,
sm3AMAM,
sm6Start,
sm2Percussion,
sm3Percussion,
} SynthMode;
//Shifts for the values contained in chandata variable
enum {
SHIFT_KSLBASE = 16,
SHIFT_KEYCODE = 24,
};
//Masks for operator 20 values
enum {
MASK_KSR = 0x10,
MASK_SUSTAIN = 0x20,
MASK_VIBRATO = 0x40,
MASK_TREMOLO = 0x80,
};
typedef enum {
OFF,
RELEASE,
SUSTAIN,
DECAY,
ATTACK,
} OperatorState;
struct _Operator {
VolumeHandler volHandler;
#if (DBOPL_WAVE == WAVE_HANDLER)
WaveHandler waveHandler; //Routine that generate a wave
#else
Bit16s* waveBase;
Bit32u waveMask;
Bit32u waveStart;
#endif
Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
Bit32u waveAdd; //The base frequency without vibrato
Bit32u waveCurrent; //waveAdd + vibratao
Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this
Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove?
Bit32u vibrato; //Scaled up vibrato strength
Bit32s sustainLevel; //When stopping at sustain level stop here
Bit32s totalLevel; //totalLevel is added to every generated volume
Bit32u currentLevel; //totalLevel + tremolo
Bit32s volume; //The currently active volume
Bit32u attackAdd; //Timers for the different states of the envelope
Bit32u decayAdd;
Bit32u releaseAdd;
Bit32u rateIndex; //Current position of the evenlope
Bit8u rateZero; //Bits for the different states of the envelope having no changes
Bit8u keyOn; //Bitmask of different values that can generate keyon
//Registers, also used to check for changes
Bit8u reg20, reg40, reg60, reg80, regE0;
//Active part of the envelope we're in
Bit8u state;
//0xff when tremolo is enabled
Bit8u tremoloMask;
//Strength of the vibrato
Bit8u vibStrength;
//Keep track of the calculated KSR so we can check for changes
Bit8u ksr;
};
struct _Channel {
Operator op[2];
SynthHandler synthHandler;
Bit32u chanData; //Frequency/octave and derived values
Bit32s old[2]; //Old data for feedback
Bit8u feedback; //Feedback shift
Bit8u regB0; //Register values to check for changes
Bit8u regC0;
//This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel
Bit8u fourMask;
Bit8s maskLeft; //Sign extended values for both channel's panning
Bit8s maskRight;
};
struct _Chip {
//This is used as the base counter for vibrato and tremolo
Bit32u lfoCounter;
Bit32u lfoAdd;
Bit32u noiseCounter;
Bit32u noiseAdd;
Bit32u noiseValue;
//Frequency scales for the different multiplications
Bit32u freqMul[16];
//Rates for decay and release for rate of this chip
Bit32u linearRates[76];
//Best match attack rates for the rate of this chip
Bit32u attackRates[76];
//18 channels with 2 operators each
Channel chan[18];
Bit8u reg104;
Bit8u reg08;
Bit8u reg04;
Bit8u regBD;
Bit8u vibratoIndex;
Bit8u tremoloIndex;
Bit8s vibratoSign;
Bit8u vibratoShift;
Bit8u tremoloValue;
Bit8u vibratoStrength;
Bit8u tremoloStrength;
//Mask for allowed wave forms
Bit8u waveFormMask;
//0 or -1 when enabled
Bit8s opl3Active;
};
/*
struct Handler : public Adlib::Handler {
DBOPL::Chip chip;
virtual Bit32u WriteAddr( Bit32u port, Bit8u val );
virtual void WriteReg( Bit32u addr, Bit8u val );
virtual void Generate( MixerChannel* chan, Bitu samples );
virtual void Init( Bitu rate );
};
*/
void Chip__Setup(Chip *self, Bit32u rate );
void DBOPL_InitTables( void );
void Chip__Chip(Chip *self);
void Chip__WriteReg(Chip *self, Bit32u reg, Bit8u val );
void Chip__GenerateBlock2(Chip *self, Bitu total, Bit32s* output );

7
opl/examples/.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
Makefile.in
Makefile
.deps
droplay
*.exe
tags
TAGS

8
opl/examples/Makefile.am Normal file
View file

@ -0,0 +1,8 @@
AM_CFLAGS = -I..
noinst_PROGRAMS=droplay
droplay_LDADD = ../libopl.a @LDFLAGS@ @SDL_LIBS@ @SDLMIXER_LIBS@
droplay_SOURCES = droplay.c

217
opl/examples/droplay.c Normal file
View file

@ -0,0 +1,217 @@
// 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:
// Demonstration program for OPL library to play back DRO
// format files.
//
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "SDL.h"
#include "opl.h"
#define HEADER_STRING "DBRAWOPL"
#define ADLIB_PORT 0x388
void WriteReg(unsigned int reg, unsigned int val)
{
int i;
// This was recorded from an OPL2, but we are probably playing
// back on an OPL3, so we need to enable the original OPL2
// channels. Doom does this already, but other games don't.
if ((reg & 0xf0) == OPL_REGS_FEEDBACK)
{
val |= 0x30;
}
OPL_WritePort(OPL_REGISTER_PORT, reg);
for (i=0; i<6; ++i)
{
OPL_ReadPort(OPL_REGISTER_PORT);
}
OPL_WritePort(OPL_DATA_PORT, val);
for (i=0; i<35; ++i)
{
OPL_ReadPort(OPL_REGISTER_PORT);
}
}
void ClearAllRegs(void)
{
int i;
for (i=0; i<=0xff; ++i)
{
WriteReg(i, 0x00);
}
}
void Init(void)
{
if (SDL_Init(SDL_INIT_TIMER) < 0)
{
fprintf(stderr, "Unable to initialise SDL timer\n");
exit(-1);
}
if (!OPL_Init(ADLIB_PORT))
{
fprintf(stderr, "Unable to initialise OPL layer\n");
exit(-1);
}
}
void Shutdown(void)
{
OPL_Shutdown();
}
struct timer_data
{
int running;
FILE *fstream;
};
void TimerCallback(void *data)
{
struct timer_data *timer_data = data;
int delay;
if (!timer_data->running)
{
return;
}
// Read data until we must make a delay.
for (;;)
{
int reg, val;
// End of file?
if (feof(timer_data->fstream))
{
timer_data->running = 0;
return;
}
reg = fgetc(timer_data->fstream);
val = fgetc(timer_data->fstream);
// Register value of 0 or 1 indicates a delay.
if (reg == 0x00)
{
delay = val;
break;
}
else if (reg == 0x01)
{
val |= (fgetc(timer_data->fstream) << 8);
delay = val;
break;
}
else
{
WriteReg(reg, val);
}
}
// Schedule the next timer callback.
OPL_SetCallback(delay, TimerCallback, timer_data);
}
void PlayFile(char *filename)
{
struct timer_data timer_data;
int running;
char buf[8];
timer_data.fstream = fopen(filename, "rb");
if (timer_data.fstream == NULL)
{
fprintf(stderr, "Failed to open %s\n", filename);
exit(-1);
}
if (fread(buf, 1, 8, timer_data.fstream) < 8)
{
fprintf(stderr, "failed to read raw OPL header\n");
exit(-1);
}
if (strncmp(buf, HEADER_STRING, 8) != 0)
{
fprintf(stderr, "Raw OPL header not found\n");
exit(-1);
}
fseek(timer_data.fstream, 28, SEEK_SET);
timer_data.running = 1;
// Start callback loop sequence.
OPL_SetCallback(0, TimerCallback, &timer_data);
// Sleep until the playback finishes.
do
{
OPL_Lock();
running = timer_data.running;
OPL_Unlock();
SDL_Delay(100);
} while (running);
fclose(timer_data.fstream);
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("Usage: %s <filename>\n", argv[0]);
exit(-1);
}
Init();
PlayFile(argv[1]);
ClearAllRegs();
Shutdown();
return 0;
}

361
opl/ioperm_sys.c Normal file
View file

@ -0,0 +1,361 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright(C) 2002, 2003 Marcel Telka
// 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:
// Interface to the ioperm.sys driver, based on code from the
// Cygwin ioperm library.
//
//-----------------------------------------------------------------------------
#ifdef _WIN32
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winioctl.h>
#include <errno.h>
#include "ioperm_sys.h"
#define IOPERM_FILE L"\\\\.\\ioperm"
#define IOCTL_IOPERM \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0xA00, METHOD_BUFFERED, FILE_ANY_ACCESS)
struct ioperm_data
{
unsigned long from;
unsigned long num;
int turn_on;
};
// Function pointers for advapi32.dll. This DLL does not exist on
// Windows 9x, so they are dynamically loaded from the DLL at runtime.
static SC_HANDLE WINAPI (*MyOpenSCManagerW)(wchar_t *lpMachineName,
wchar_t *lpDatabaseName,
DWORD dwDesiredAccess) = NULL;
static SC_HANDLE WINAPI (*MyCreateServiceW)(SC_HANDLE hSCManager,
wchar_t *lpServiceName,
wchar_t *lpDisplayName,
DWORD dwDesiredAccess,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
wchar_t *lpBinaryPathName,
wchar_t *lpLoadOrderGroup,
LPDWORD lpdwTagId,
wchar_t *lpDependencies,
wchar_t *lpServiceStartName,
wchar_t *lpPassword);
static SC_HANDLE WINAPI (*MyOpenServiceW)(SC_HANDLE hSCManager,
wchar_t *lpServiceName,
DWORD dwDesiredAccess);
static BOOL WINAPI (*MyStartServiceW)(SC_HANDLE hService,
DWORD dwNumServiceArgs,
wchar_t **lpServiceArgVectors);
static BOOL WINAPI (*MyControlService)(SC_HANDLE hService,
DWORD dwControl,
LPSERVICE_STATUS lpServiceStatus);
static BOOL WINAPI (*MyCloseServiceHandle)(SC_HANDLE hSCObject);
static BOOL WINAPI (*MyDeleteService)(SC_HANDLE hService);
static struct
{
char *name;
void **fn;
} dll_functions[] = {
{ "OpenSCManagerW", (void **) &MyOpenSCManagerW },
{ "CreateServiceW", (void **) &MyCreateServiceW },
{ "OpenServiceW", (void **) &MyOpenServiceW },
{ "StartServiceW", (void **) &MyStartServiceW },
{ "ControlService", (void **) &MyControlService },
{ "CloseServiceHandle", (void **) &MyCloseServiceHandle },
{ "DeleteService", (void **) &MyDeleteService },
};
// Globals
static SC_HANDLE scm = NULL;
static SC_HANDLE svc = NULL;
static int service_was_created = 0;
static int service_was_started = 0;
static int LoadLibraryPointers(void)
{
HMODULE dll;
int i;
// Already loaded?
if (MyOpenSCManagerW != NULL)
{
return 1;
}
dll = LoadLibraryW(L"advapi32.dll");
if (dll == NULL)
{
fprintf(stderr, "LoadLibraryPointers: Failed to open advapi32.dll\n");
return 0;
}
for (i = 0; i < sizeof(dll_functions) / sizeof(*dll_functions); ++i)
{
*dll_functions[i].fn = GetProcAddress(dll, dll_functions[i].name);
if (*dll_functions[i].fn == NULL)
{
fprintf(stderr, "LoadLibraryPointers: Failed to get address "
"for '%s'\n", dll_functions[i].name);
return 0;
}
}
return 1;
}
int IOperm_EnablePortRange(unsigned int from, unsigned int num, int turn_on)
{
HANDLE h;
struct ioperm_data ioperm_data;
DWORD BytesReturned;
BOOL r;
h = CreateFileW(IOPERM_FILE, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE)
{
errno = ENODEV;
return -1;
}
ioperm_data.from = from;
ioperm_data.num = num;
ioperm_data.turn_on = turn_on;
r = DeviceIoControl(h, IOCTL_IOPERM,
&ioperm_data, sizeof ioperm_data,
NULL, 0,
&BytesReturned, NULL);
if (!r)
{
errno = EPERM;
}
CloseHandle(h);
return r != 0;
}
// Load ioperm.sys driver.
// Returns 1 for success, 0 for failure.
// Remember to call IOperm_UninstallDriver to uninstall the driver later.
int IOperm_InstallDriver(void)
{
wchar_t driver_path[MAX_PATH];
int error;
int result = 1;
if (!LoadLibraryPointers())
{
return 0;
}
scm = MyOpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (scm == NULL)
{
error = GetLastError();
fprintf(stderr, "IOperm_InstallDriver: OpenSCManager failed (%i).\n",
error);
return 0;
}
// Get the full path to the driver file.
GetFullPathNameW(L"ioperm.sys", MAX_PATH, driver_path, NULL);
// Create the service.
svc = MyCreateServiceW(scm,
L"ioperm",
L"ioperm support for Cygwin driver",
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
driver_path,
NULL,
NULL,
NULL,
NULL,
NULL);
if (svc == NULL)
{
error = GetLastError();
if (error != ERROR_SERVICE_EXISTS)
{
fprintf(stderr,
"IOperm_InstallDriver: Failed to create service (%i).\n",
error);
}
else
{
svc = MyOpenServiceW(scm, L"ioperm", SERVICE_ALL_ACCESS);
if (svc == NULL)
{
error = GetLastError();
fprintf(stderr,
"IOperm_InstallDriver: Failed to open service (%i).\n",
error);
}
}
if (svc == NULL)
{
MyCloseServiceHandle(scm);
return 0;
}
}
else
{
service_was_created = 1;
}
// Start the service. If the service already existed, it might have
// already been running as well.
if (!MyStartServiceW(svc, 0, NULL))
{
error = GetLastError();
if (error != ERROR_SERVICE_ALREADY_RUNNING)
{
fprintf(stderr, "IOperm_InstallDriver: Failed to start service (%i).\n",
error);
result = 0;
}
else
{
printf("IOperm_InstallDriver: ioperm driver already running.\n");
}
}
else
{
printf("IOperm_InstallDriver: ioperm driver installed.\n");
service_was_started = 1;
}
// If we failed to start the driver running, we need to clean up
// before finishing.
if (result == 0)
{
IOperm_UninstallDriver();
}
return result;
}
int IOperm_UninstallDriver(void)
{
SERVICE_STATUS stat;
int result = 1;
int error;
// If we started the service, stop it.
if (service_was_started)
{
if (!MyControlService(svc, SERVICE_CONTROL_STOP, &stat))
{
error = GetLastError();
if (error == ERROR_SERVICE_NOT_ACTIVE)
{
fprintf(stderr,
"IOperm_UninstallDriver: Service not active? (%i)\n",
error);
}
else
{
fprintf(stderr,
"IOperm_UninstallDriver: Failed to stop service (%i).\n",
error);
result = 0;
}
}
}
// If we created the service, delete it.
if (service_was_created)
{
if (!MyDeleteService(svc))
{
error = GetLastError();
fprintf(stderr,
"IOperm_UninstallDriver: DeleteService failed (%i).\n",
error);
result = 0;
}
else if (service_was_started)
{
printf("IOperm_UnInstallDriver: ioperm driver uninstalled.\n");
}
}
// Close handles.
if (svc != NULL)
{
MyCloseServiceHandle(svc);
svc = NULL;
}
if (scm != NULL)
{
MyCloseServiceHandle(scm);
scm = NULL;
}
service_was_created = 0;
service_was_started = 0;
return result;
}
#endif /* #ifndef _WIN32 */

36
opl/ioperm_sys.h Normal file
View file

@ -0,0 +1,36 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright(C) 2002, 2003 Marcel Telka
// 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:
// Interface to the ioperm.sys driver, based on code from the
// Cygwin ioperm library.
//
//-----------------------------------------------------------------------------
#ifndef IOPERM_SYS_H
#define IOPERM_SYS_H
int IOperm_EnablePortRange(unsigned int from, unsigned int num, int turn_on);
int IOperm_InstallDriver(void);
int IOperm_UninstallDriver(void);
#endif /* #ifndef IOPERM_SYS_H */

466
opl/opl.c Normal file
View file

@ -0,0 +1,466 @@
// 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:
// OPL interface.
//
//-----------------------------------------------------------------------------
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32_WCE
#include "libc_wince.h"
#endif
#include "SDL.h"
#include "opl.h"
#include "opl_internal.h"
//#define OPL_DEBUG_TRACE
#ifdef HAVE_IOPERM
extern opl_driver_t opl_linux_driver;
#endif
#if defined(HAVE_LIBI386) || defined(HAVE_LIBAMD64)
extern opl_driver_t opl_openbsd_driver;
#endif
#ifdef _WIN32
extern opl_driver_t opl_win32_driver;
#endif
extern opl_driver_t opl_sdl_driver;
static opl_driver_t *drivers[] =
{
#ifdef HAVE_IOPERM
&opl_linux_driver,
#endif
#if defined(HAVE_LIBI386) || defined(HAVE_LIBAMD64)
&opl_openbsd_driver,
#endif
#ifdef _WIN32
&opl_win32_driver,
#endif
&opl_sdl_driver,
NULL
};
static opl_driver_t *driver = NULL;
static int init_stage_reg_writes = 1;
unsigned int opl_sample_rate = 22050;
//
// Init/shutdown code.
//
// Initialize the specified driver and detect an OPL chip. Returns
// true if an OPL is detected.
static int InitDriver(opl_driver_t *_driver, unsigned int port_base)
{
// Initialize the driver.
if (!_driver->init_func(port_base))
{
return 0;
}
// The driver was initialized okay, so we now have somewhere
// to write to. It doesn't mean there's an OPL chip there,
// though. Perform the detection sequence to make sure.
// (it's done twice, like how Doom does it).
driver = _driver;
init_stage_reg_writes = 1;
if (!OPL_Detect() || !OPL_Detect())
{
printf("OPL_Init: No OPL detected using '%s' driver.\n", _driver->name);
_driver->shutdown_func();
driver = NULL;
return 0;
}
// Initialize all registers.
OPL_InitRegisters();
init_stage_reg_writes = 0;
printf("OPL_Init: Using driver '%s'.\n", driver->name);
return 1;
}
// Find a driver automatically by trying each in the list.
static int AutoSelectDriver(unsigned int port_base)
{
int i;
for (i=0; drivers[i] != NULL; ++i)
{
if (InitDriver(drivers[i], port_base))
{
return 1;
}
}
printf("OPL_Init: Failed to find a working driver.\n");
return 0;
}
// Initialize the OPL library. Returns true if initialized
// successfully.
int OPL_Init(unsigned int port_base)
{
char *driver_name;
int i;
driver_name = getenv("OPL_DRIVER");
if (driver_name != NULL)
{
// Search the list until we find the driver with this name.
for (i=0; drivers[i] != NULL; ++i)
{
if (!strcmp(driver_name, drivers[i]->name))
{
if (InitDriver(drivers[i], port_base))
{
return 1;
}
else
{
printf("OPL_Init: Failed to initialize "
"driver: '%s'.\n", driver_name);
return 0;
}
}
}
printf("OPL_Init: unknown driver: '%s'.\n", driver_name);
return 0;
}
else
{
return AutoSelectDriver(port_base);
}
}
// Shut down the OPL library.
void OPL_Shutdown(void)
{
if (driver != NULL)
{
driver->shutdown_func();
driver = NULL;
}
}
// Set the sample rate used for software OPL emulation.
void OPL_SetSampleRate(unsigned int rate)
{
opl_sample_rate = rate;
}
void OPL_WritePort(opl_port_t port, unsigned int value)
{
if (driver != NULL)
{
#ifdef OPL_DEBUG_TRACE
printf("OPL_write: %i, %x\n", port, value);
fflush(stdout);
#endif
driver->write_port_func(port, value);
}
}
unsigned int OPL_ReadPort(opl_port_t port)
{
if (driver != NULL)
{
unsigned int result;
#ifdef OPL_DEBUG_TRACE
printf("OPL_read: %i...\n", port);
fflush(stdout);
#endif
result = driver->read_port_func(port);
#ifdef OPL_DEBUG_TRACE
printf("OPL_read: %i -> %x\n", port, result);
fflush(stdout);
#endif
return result;
}
else
{
return 0;
}
}
//
// Higher-level functions, based on the lower-level functions above
// (register write, etc).
//
unsigned int OPL_ReadStatus(void)
{
return OPL_ReadPort(OPL_REGISTER_PORT);
}
// Write an OPL register value
void OPL_WriteRegister(int reg, int value)
{
int i;
OPL_WritePort(OPL_REGISTER_PORT, reg);
// For timing, read the register port six times after writing the
// register number to cause the appropriate delay
for (i=0; i<6; ++i)
{
// An oddity of the Doom OPL code: at startup initialization,
// the spacing here is performed by reading from the register
// port; after initialization, the data port is read, instead.
if (init_stage_reg_writes)
{
OPL_ReadPort(OPL_REGISTER_PORT);
}
else
{
OPL_ReadPort(OPL_DATA_PORT);
}
}
OPL_WritePort(OPL_DATA_PORT, value);
// Read the register port 24 times after writing the value to
// cause the appropriate delay
for (i=0; i<24; ++i)
{
OPL_ReadStatus();
}
}
// Detect the presence of an OPL chip
int OPL_Detect(void)
{
int result1, result2;
int i;
// Reset both timers:
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x60);
// Enable interrupts:
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x80);
// Read status
result1 = OPL_ReadStatus();
// Set timer:
OPL_WriteRegister(OPL_REG_TIMER1, 0xff);
// Start timer 1:
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x21);
// Wait for 80 microseconds
// This is how Doom does it:
for (i=0; i<200; ++i)
{
OPL_ReadStatus();
}
OPL_Delay(1);
// Read status
result2 = OPL_ReadStatus();
// Reset both timers:
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x60);
// Enable interrupts:
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x80);
return (result1 & 0xe0) == 0x00
&& (result2 & 0xe0) == 0xc0;
}
// Initialize registers on startup
void OPL_InitRegisters(void)
{
int r;
// Initialize level registers
for (r=OPL_REGS_LEVEL; r <= OPL_REGS_LEVEL + OPL_NUM_OPERATORS; ++r)
{
OPL_WriteRegister(r, 0x3f);
}
// Initialize other registers
// These two loops write to registers that actually don't exist,
// but this is what Doom does ...
// Similarly, the <= is also intenational.
for (r=OPL_REGS_ATTACK; r <= OPL_REGS_WAVEFORM + OPL_NUM_OPERATORS; ++r)
{
OPL_WriteRegister(r, 0x00);
}
// More registers ...
for (r=1; r < OPL_REGS_LEVEL; ++r)
{
OPL_WriteRegister(r, 0x00);
}
// Re-initialize the low registers:
// Reset both timers and enable interrupts:
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x60);
OPL_WriteRegister(OPL_REG_TIMER_CTRL, 0x80);
// "Allow FM chips to control the waveform of each operator":
OPL_WriteRegister(OPL_REG_WAVEFORM_ENABLE, 0x20);
// Keyboard split point on (?)
OPL_WriteRegister(OPL_REG_FM_MODE, 0x40);
}
//
// Timer functions.
//
void OPL_SetCallback(unsigned int ms, opl_callback_t callback, void *data)
{
if (driver != NULL)
{
driver->set_callback_func(ms, callback, data);
}
}
void OPL_ClearCallbacks(void)
{
if (driver != NULL)
{
driver->clear_callbacks_func();
}
}
void OPL_Lock(void)
{
if (driver != NULL)
{
driver->lock_func();
}
}
void OPL_Unlock(void)
{
if (driver != NULL)
{
driver->unlock_func();
}
}
typedef struct
{
int finished;
SDL_mutex *mutex;
SDL_cond *cond;
} delay_data_t;
static void DelayCallback(void *_delay_data)
{
delay_data_t *delay_data = _delay_data;
SDL_LockMutex(delay_data->mutex);
delay_data->finished = 1;
SDL_CondSignal(delay_data->cond);
SDL_UnlockMutex(delay_data->mutex);
}
void OPL_Delay(unsigned int ms)
{
delay_data_t delay_data;
if (driver == NULL)
{
return;
}
// Create a callback that will signal this thread after the
// specified time.
delay_data.finished = 0;
delay_data.mutex = SDL_CreateMutex();
delay_data.cond = SDL_CreateCond();
OPL_SetCallback(ms, DelayCallback, &delay_data);
// Wait until the callback is invoked.
SDL_LockMutex(delay_data.mutex);
while (!delay_data.finished)
{
SDL_CondWait(delay_data.cond, delay_data.mutex);
}
SDL_UnlockMutex(delay_data.mutex);
// Clean up.
SDL_DestroyMutex(delay_data.mutex);
SDL_DestroyCond(delay_data.cond);
}
void OPL_SetPaused(int paused)
{
if (driver != NULL)
{
driver->set_paused_func(paused);
}
}

137
opl/opl.h Normal file
View file

@ -0,0 +1,137 @@
// 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:
// OPL interface.
//
//-----------------------------------------------------------------------------
#ifndef OPL_OPL_H
#define OPL_OPL_H
typedef void (*opl_callback_t)(void *data);
typedef enum
{
OPL_REGISTER_PORT = 0,
OPL_DATA_PORT = 1
} opl_port_t;
#define OPL_NUM_OPERATORS 21
#define OPL_NUM_VOICES 9
#define OPL_REG_WAVEFORM_ENABLE 0x01
#define OPL_REG_TIMER1 0x02
#define OPL_REG_TIMER2 0x03
#define OPL_REG_TIMER_CTRL 0x04
#define OPL_REG_FM_MODE 0x08
// Operator registers (21 of each):
#define OPL_REGS_TREMOLO 0x20
#define OPL_REGS_LEVEL 0x40
#define OPL_REGS_ATTACK 0x60
#define OPL_REGS_SUSTAIN 0x80
#define OPL_REGS_WAVEFORM 0xE0
// Voice registers (9 of each):
#define OPL_REGS_FREQ_1 0xA0
#define OPL_REGS_FREQ_2 0xB0
#define OPL_REGS_FEEDBACK 0xC0
//
// Low-level functions.
//
// Initialize the OPL subsystem.
int OPL_Init(unsigned int port_base);
// Shut down the OPL subsystem.
void OPL_Shutdown(void);
// Set the sample rate used for software emulation.
void OPL_SetSampleRate(unsigned int rate);
// Write to one of the OPL I/O ports:
void OPL_WritePort(opl_port_t port, unsigned int value);
// Read from one of the OPL I/O ports:
unsigned int OPL_ReadPort(opl_port_t port);
//
// Higher-level functions.
//
// Read the cuurrent status byte of the OPL chip.
unsigned int OPL_ReadStatus(void);
// Write to an OPL register.
void OPL_WriteRegister(int reg, int value);
// Perform a detection sequence to determine that an
// OPL chip is present.
int OPL_Detect(void);
// Initialize all registers, performed on startup.
void OPL_InitRegisters(void);
//
// Timer callback functions.
//
// Set a timer callback. After the specified number of milliseconds
// have elapsed, the callback will be invoked.
void OPL_SetCallback(unsigned int ms, opl_callback_t callback, void *data);
// Clear all OPL callbacks that have been set.
void OPL_ClearCallbacks(void);
// Begin critical section, during which, OPL callbacks will not be
// invoked.
void OPL_Lock(void);
// End critical section.
void OPL_Unlock(void);
// Block until the specified number of milliseconds have elapsed.
void OPL_Delay(unsigned int ms);
// Pause the OPL callbacks.
void OPL_SetPaused(int paused);
#endif

64
opl/opl_internal.h Normal file
View file

@ -0,0 +1,64 @@
// 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:
// OPL internal interface.
//
//-----------------------------------------------------------------------------
#ifndef OPL_INTERNAL_H
#define OPL_INTERNAL_H
#include "opl.h"
typedef int (*opl_init_func)(unsigned int port_base);
typedef void (*opl_shutdown_func)(void);
typedef unsigned int (*opl_read_port_func)(opl_port_t port);
typedef void (*opl_write_port_func)(opl_port_t port, unsigned int value);
typedef void (*opl_set_callback_func)(unsigned int ms,
opl_callback_t callback,
void *data);
typedef void (*opl_clear_callbacks_func)(void);
typedef void (*opl_lock_func)(void);
typedef void (*opl_unlock_func)(void);
typedef void (*opl_set_paused_func)(int paused);
typedef struct
{
char *name;
opl_init_func init_func;
opl_shutdown_func shutdown_func;
opl_read_port_func read_port_func;
opl_write_port_func write_port_func;
opl_set_callback_func set_callback_func;
opl_clear_callbacks_func clear_callbacks_func;
opl_lock_func lock_func;
opl_unlock_func unlock_func;
opl_set_paused_func set_paused_func;
} opl_driver_t;
// Sample rate to use when doing software emulation.
extern unsigned int opl_sample_rate;
#endif /* #ifndef OPL_INTERNAL_H */

110
opl/opl_linux.c Normal file
View file

@ -0,0 +1,110 @@
// 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:
// OPL Linux interface.
//
//-----------------------------------------------------------------------------
#include "config.h"
#ifdef HAVE_IOPERM
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/io.h>
#include "opl.h"
#include "opl_internal.h"
#include "opl_timer.h"
static unsigned int opl_port_base;
static int OPL_Linux_Init(unsigned int port_base)
{
// Try to get permissions:
if (ioperm(port_base, 2, 1) < 0)
{
fprintf(stderr, "Failed to get I/O port permissions for 0x%x: %s\n",
port_base, strerror(errno));
if (errno == EPERM)
{
fprintf(stderr,
"\tYou may need to run the program as root in order\n"
"\tto acquire I/O port permissions for OPL MIDI playback.\n");
}
return 0;
}
opl_port_base = port_base;
// Start callback thread
if (!OPL_Timer_StartThread())
{
ioperm(port_base, 2, 0);
return 0;
}
return 1;
}
static void OPL_Linux_Shutdown(void)
{
// Stop callback thread
OPL_Timer_StopThread();
// Release permissions
ioperm(opl_port_base, 2, 0);
}
static unsigned int OPL_Linux_PortRead(opl_port_t port)
{
return inb(opl_port_base + port);
}
static void OPL_Linux_PortWrite(opl_port_t port, unsigned int value)
{
outb(value, opl_port_base + port);
}
opl_driver_t opl_linux_driver =
{
"Linux",
OPL_Linux_Init,
OPL_Linux_Shutdown,
OPL_Linux_PortRead,
OPL_Linux_PortWrite,
OPL_Timer_SetCallback,
OPL_Timer_ClearCallbacks,
OPL_Timer_Lock,
OPL_Timer_Unlock,
OPL_Timer_SetPaused
};
#endif /* #ifdef HAVE_IOPERM */

125
opl/opl_obsd.c Normal file
View file

@ -0,0 +1,125 @@
// 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:
// OPL OpenBSD interface (also NetBSD)
//
//-----------------------------------------------------------------------------
#include "config.h"
// OpenBSD has a i386_iopl on i386 and amd64_iopl on x86_64,
// even though they do the same thing. Take care of this
// here, and map set_iopl to point to the appropriate name.
#if defined(HAVE_LIBI386)
#include <sys/types.h>
#include <machine/sysarch.h>
#include <i386/pio.h>
#define set_iopl i386_iopl
#elif defined(HAVE_LIBAMD64)
#include <sys/types.h>
#include <machine/sysarch.h>
#include <amd64/pio.h>
#define set_iopl amd64_iopl
#else
#define NO_OBSD_DRIVER
#endif
// If the above succeeded, proceed with the rest.
#ifndef NO_OBSD_DRIVER
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "opl.h"
#include "opl_internal.h"
#include "opl_timer.h"
static unsigned int opl_port_base;
static int OPL_OpenBSD_Init(unsigned int port_base)
{
// Try to get permissions:
if (set_iopl(3) < 0)
{
fprintf(stderr, "Failed to get raise I/O privilege level: "
"check that you are running as root.\n");
return 0;
}
opl_port_base = port_base;
// Start callback thread
if (!OPL_Timer_StartThread())
{
set_iopl(0);
return 0;
}
return 1;
}
static void OPL_OpenBSD_Shutdown(void)
{
// Stop callback thread
OPL_Timer_StopThread();
// Release I/O port permissions:
set_iopl(0);
}
static unsigned int OPL_OpenBSD_PortRead(opl_port_t port)
{
return inb(opl_port_base + port);
}
static void OPL_OpenBSD_PortWrite(opl_port_t port, unsigned int value)
{
outb(opl_port_base + port, value);
}
opl_driver_t opl_openbsd_driver =
{
"OpenBSD",
OPL_OpenBSD_Init,
OPL_OpenBSD_Shutdown,
OPL_OpenBSD_PortRead,
OPL_OpenBSD_PortWrite,
OPL_Timer_SetCallback,
OPL_Timer_ClearCallbacks,
OPL_Timer_Lock,
OPL_Timer_Unlock,
OPL_Timer_SetPaused
};
#endif /* #ifndef NO_OBSD_DRIVER */

280
opl/opl_queue.c Normal file
View file

@ -0,0 +1,280 @@
// 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:
// Queue of waiting callbacks, stored in a binary min heap, so that we
// can always get the first callback.
//
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "opl_queue.h"
#define MAX_OPL_QUEUE 64
typedef struct
{
opl_callback_t callback;
void *data;
unsigned int time;
} opl_queue_entry_t;
struct opl_callback_queue_s
{
opl_queue_entry_t entries[MAX_OPL_QUEUE];
unsigned int num_entries;
};
opl_callback_queue_t *OPL_Queue_Create(void)
{
opl_callback_queue_t *queue;
queue = malloc(sizeof(opl_callback_queue_t));
queue->num_entries = 0;
return queue;
}
void OPL_Queue_Destroy(opl_callback_queue_t *queue)
{
free(queue);
}
int OPL_Queue_IsEmpty(opl_callback_queue_t *queue)
{
return queue->num_entries == 0;
}
void OPL_Queue_Clear(opl_callback_queue_t *queue)
{
queue->num_entries = 0;
}
void OPL_Queue_Push(opl_callback_queue_t *queue,
opl_callback_t callback, void *data,
unsigned int time)
{
int entry_id;
int parent_id;
if (queue->num_entries >= MAX_OPL_QUEUE)
{
fprintf(stderr, "OPL_Queue_Push: Exceeded maximum callbacks\n");
return;
}
// Add to last queue entry.
entry_id = queue->num_entries;
++queue->num_entries;
// Shift existing entries down in the heap.
while (entry_id > 0)
{
parent_id = (entry_id - 1) / 2;
// Is the heap condition satisfied?
if (time >= queue->entries[parent_id].time)
{
break;
}
// Move the existing entry down in the heap.
memcpy(&queue->entries[entry_id],
&queue->entries[parent_id],
sizeof(opl_queue_entry_t));
// Advance to the parent.
entry_id = parent_id;
}
// Insert new callback data.
queue->entries[entry_id].callback = callback;
queue->entries[entry_id].data = data;
queue->entries[entry_id].time = time;
}
int OPL_Queue_Pop(opl_callback_queue_t *queue,
opl_callback_t *callback, void **data)
{
opl_queue_entry_t *entry;
int child1, child2;
int i, next_i;
// Empty?
if (queue->num_entries <= 0)
{
return 0;
}
// Store the result:
*callback = queue->entries[0].callback;
*data = queue->entries[0].data;
// Decrease the heap size, and keep pointer to the last entry in
// the heap, which must now be percolated down from the top.
--queue->num_entries;
entry = &queue->entries[queue->num_entries];
// Percolate down.
i = 0;
for (;;)
{
child1 = i * 2 + 1;
child2 = i * 2 + 2;
if (child1 < queue->num_entries
&& queue->entries[child1].time < entry->time)
{
// Left child is less than entry.
// Use the minimum of left and right children.
if (child2 < queue->num_entries
&& queue->entries[child2].time < queue->entries[child1].time)
{
next_i = child2;
}
else
{
next_i = child1;
}
}
else if (child2 < queue->num_entries
&& queue->entries[child2].time < entry->time)
{
// Right child is less than entry. Go down the right side.
next_i = child2;
}
else
{
// Finished percolating.
break;
}
// Percolate the next value up and advance.
memcpy(&queue->entries[i],
&queue->entries[next_i],
sizeof(opl_queue_entry_t));
i = next_i;
}
// Store the old last-entry at its new position.
memcpy(&queue->entries[i], entry, sizeof(opl_queue_entry_t));
return 1;
}
unsigned int OPL_Queue_Peek(opl_callback_queue_t *queue)
{
if (queue->num_entries > 0)
{
return queue->entries[0].time;
}
else
{
return 0;
}
}
#ifdef TEST
#include <assert.h>
static void PrintQueueNode(opl_callback_queue_t *queue, int node, int depth)
{
int i;
if (node >= queue->num_entries)
{
return;
}
for (i=0; i<depth * 3; ++i)
{
printf(" ");
}
printf("%i\n", queue->entries[node].time);
PrintQueueNode(queue, node * 2 + 1, depth + 1);
PrintQueueNode(queue, node * 2 + 2, depth + 1);
}
static void PrintQueue(opl_callback_queue_t *queue)
{
PrintQueueNode(queue, 0, 0);
}
int main()
{
opl_callback_queue_t *queue;
int iteration;
queue = OPL_Queue_Create();
for (iteration=0; iteration<5000; ++iteration)
{
opl_callback_t callback;
void *data;
unsigned int time;
unsigned int newtime;
int i;
for (i=0; i<MAX_OPL_QUEUE; ++i)
{
time = rand() % 0x10000;
OPL_Queue_Push(queue, NULL, NULL, time);
}
time = 0;
for (i=0; i<MAX_OPL_QUEUE; ++i)
{
assert(!OPL_Queue_IsEmpty(queue));
newtime = OPL_Queue_Peek(queue);
assert(OPL_Queue_Pop(queue, &callback, &data));
assert(newtime >= time);
time = newtime;
}
assert(OPL_Queue_IsEmpty(queue));
assert(!OPL_Queue_Pop(queue, &callback, &data));
}
}
#endif

45
opl/opl_queue.h Normal file
View file

@ -0,0 +1,45 @@
// 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:
// OPL callback queue.
//
//-----------------------------------------------------------------------------
#ifndef OPL_QUEUE_H
#define OPL_QUEUE_H
#include "opl.h"
typedef struct opl_callback_queue_s opl_callback_queue_t;
opl_callback_queue_t *OPL_Queue_Create(void);
int OPL_Queue_IsEmpty(opl_callback_queue_t *queue);
void OPL_Queue_Clear(opl_callback_queue_t *queue);
void OPL_Queue_Destroy(opl_callback_queue_t *queue);
void OPL_Queue_Push(opl_callback_queue_t *queue,
opl_callback_t callback, void *data,
unsigned int time);
int OPL_Queue_Pop(opl_callback_queue_t *queue,
opl_callback_t *callback, void **data);
unsigned int OPL_Queue_Peek(opl_callback_queue_t *queue);
#endif /* #ifndef OPL_QUEUE_H */

510
opl/opl_sdl.c Normal file
View file

@ -0,0 +1,510 @@
// 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:
// OPL SDL interface.
//
//-----------------------------------------------------------------------------
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "SDL.h"
#include "SDL_mixer.h"
#include "dbopl.h"
#include "opl.h"
#include "opl_internal.h"
#include "opl_queue.h"
#define MAX_SOUND_SLICE_TIME 100 /* ms */
typedef struct
{
unsigned int rate; // Number of times the timer is advanced per sec.
unsigned int enabled; // Non-zero if timer is enabled.
unsigned int value; // Last value that was set.
unsigned int expire_time; // Calculated time that timer will expire.
} opl_timer_t;
// When the callback mutex is locked using OPL_Lock, callback functions
// are not invoked.
static SDL_mutex *callback_mutex = NULL;
// Queue of callbacks waiting to be invoked.
static opl_callback_queue_t *callback_queue;
// Mutex used to control access to the callback queue.
static SDL_mutex *callback_queue_mutex = NULL;
// Current time, in number of samples since startup:
static int current_time;
// If non-zero, playback is currently paused.
static int opl_sdl_paused;
// Time offset (in samples) due to the fact that callbacks
// were previously paused.
static unsigned int pause_offset;
// OPL software emulator structure.
static Chip opl_chip;
// Temporary mixing buffer used by the mixing callback.
static int32_t *mix_buffer = NULL;
// Register number that was written.
static int register_num = 0;
// Timers; DBOPL does not do timer stuff itself.
static opl_timer_t timer1 = { 12500, 0, 0, 0 };
static opl_timer_t timer2 = { 3125, 0, 0, 0 };
// SDL parameters.
static int sdl_was_initialized = 0;
static int mixing_freq, mixing_channels;
static Uint16 mixing_format;
static int SDLIsInitialized(void)
{
int freq, channels;
Uint16 format;
return Mix_QuerySpec(&freq, &format, &channels);
}
// Advance time by the specified number of samples, invoking any
// callback functions as appropriate.
static void AdvanceTime(unsigned int nsamples)
{
opl_callback_t callback;
void *callback_data;
SDL_LockMutex(callback_queue_mutex);
// Advance time.
current_time += nsamples;
if (opl_sdl_paused)
{
pause_offset += nsamples;
}
// Are there callbacks to invoke now? Keep invoking them
// until there are none more left.
while (!OPL_Queue_IsEmpty(callback_queue)
&& current_time >= OPL_Queue_Peek(callback_queue) + pause_offset)
{
// Pop the callback from the queue to invoke it.
if (!OPL_Queue_Pop(callback_queue, &callback, &callback_data))
{
break;
}
// The mutex stuff here is a bit complicated. We must
// hold callback_mutex when we invoke the callback (so that
// the control thread can use OPL_Lock() to prevent callbacks
// from being invoked), but we must not be holding
// callback_queue_mutex, as the callback must be able to
// call OPL_SetCallback to schedule new callbacks.
SDL_UnlockMutex(callback_queue_mutex);
SDL_LockMutex(callback_mutex);
callback(callback_data);
SDL_UnlockMutex(callback_mutex);
SDL_LockMutex(callback_queue_mutex);
}
SDL_UnlockMutex(callback_queue_mutex);
}
// Call the OPL emulator code to fill the specified buffer.
static void FillBuffer(int16_t *buffer, unsigned int nsamples)
{
unsigned int i;
// This seems like a reasonable assumption. mix_buffer is
// 1 second long, which should always be much longer than the
// SDL mix buffer.
assert(nsamples < mixing_freq);
Chip__GenerateBlock2(&opl_chip, nsamples, mix_buffer);
// Mix into the destination buffer, doubling up into stereo.
for (i=0; i<nsamples; ++i)
{
buffer[i * 2] = (int16_t) (mix_buffer[i] * 2);
buffer[i * 2 + 1] = (int16_t) (mix_buffer[i] * 2);
}
}
// Callback function to fill a new sound buffer:
static void OPL_Mix_Callback(void *udata,
Uint8 *byte_buffer,
int buffer_bytes)
{
int16_t *buffer;
unsigned int buffer_len;
unsigned int filled = 0;
// Buffer length in samples (quadrupled, because of 16-bit and stereo)
buffer = (int16_t *) byte_buffer;
buffer_len = buffer_bytes / 4;
// Repeatedly call the OPL emulator update function until the buffer is
// full.
while (filled < buffer_len)
{
unsigned int next_callback_time;
unsigned int nsamples;
SDL_LockMutex(callback_queue_mutex);
// Work out the time until the next callback waiting in
// the callback queue must be invoked. We can then fill the
// buffer with this many samples.
if (opl_sdl_paused || OPL_Queue_IsEmpty(callback_queue))
{
nsamples = buffer_len - filled;
}
else
{
next_callback_time = OPL_Queue_Peek(callback_queue) + pause_offset;
nsamples = next_callback_time - current_time;
if (nsamples > buffer_len - filled)
{
nsamples = buffer_len - filled;
}
}
SDL_UnlockMutex(callback_queue_mutex);
// Add emulator output to buffer.
FillBuffer(buffer + filled * 2, nsamples);
filled += nsamples;
// Invoke callbacks for this point in time.
AdvanceTime(nsamples);
}
}
static void OPL_SDL_Shutdown(void)
{
Mix_HookMusic(NULL, NULL);
if (sdl_was_initialized)
{
Mix_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
OPL_Queue_Destroy(callback_queue);
free(mix_buffer);
sdl_was_initialized = 0;
}
/*
if (opl_chip != NULL)
{
OPLDestroy(opl_chip);
opl_chip = NULL;
}
*/
if (callback_mutex != NULL)
{
SDL_DestroyMutex(callback_mutex);
callback_mutex = NULL;
}
if (callback_queue_mutex != NULL)
{
SDL_DestroyMutex(callback_queue_mutex);
callback_queue_mutex = NULL;
}
}
static unsigned int GetSliceSize(void)
{
int limit;
int n;
limit = (opl_sample_rate * MAX_SOUND_SLICE_TIME) / 1000;
// Try all powers of two, not exceeding the limit.
for (n=0;; ++n)
{
// 2^n <= limit < 2^n+1 ?
if ((1 << (n + 1)) > limit)
{
return (1 << n);
}
}
// Should never happen?
return 1024;
}
static int OPL_SDL_Init(unsigned int port_base)
{
// Check if SDL_mixer has been opened already
// If not, we must initialize it now
if (!SDLIsInitialized())
{
if (SDL_Init(SDL_INIT_AUDIO) < 0)
{
fprintf(stderr, "Unable to set up sound.\n");
return 0;
}
if (Mix_OpenAudio(opl_sample_rate, AUDIO_S16SYS, 2, GetSliceSize()) < 0)
{
fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError());
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return 0;
}
SDL_PauseAudio(0);
// When this module shuts down, it has the responsibility to
// shut down SDL.
sdl_was_initialized = 1;
}
else
{
sdl_was_initialized = 0;
}
opl_sdl_paused = 0;
pause_offset = 0;
// Queue structure of callbacks to invoke.
callback_queue = OPL_Queue_Create();
current_time = 0;
// Get the mixer frequency, format and number of channels.
Mix_QuerySpec(&mixing_freq, &mixing_format, &mixing_channels);
// Only supports AUDIO_S16SYS
if (mixing_format != AUDIO_S16SYS || mixing_channels != 2)
{
fprintf(stderr,
"OPL_SDL only supports native signed 16-bit LSB, "
"stereo format!\n");
OPL_SDL_Shutdown();
return 0;
}
// Mix buffer:
mix_buffer = malloc(mixing_freq * sizeof(uint32_t));
// Create the emulator structure:
DBOPL_InitTables();
Chip__Chip(&opl_chip);
Chip__Setup(&opl_chip, mixing_freq);
callback_mutex = SDL_CreateMutex();
callback_queue_mutex = SDL_CreateMutex();
// TODO: This should be music callback? or-?
Mix_HookMusic(OPL_Mix_Callback, NULL);
return 1;
}
static unsigned int OPL_SDL_PortRead(opl_port_t port)
{
unsigned int result = 0;
if (timer1.enabled && current_time > timer1.expire_time)
{
result |= 0x80; // Either have expired
result |= 0x40; // Timer 1 has expired
}
if (timer2.enabled && current_time > timer2.expire_time)
{
result |= 0x80; // Either have expired
result |= 0x20; // Timer 2 has expired
}
return result;
}
static void OPLTimer_CalculateEndTime(opl_timer_t *timer)
{
int tics;
// If the timer is enabled, calculate the time when the timer
// will expire.
if (timer->enabled)
{
tics = 0x100 - timer->value;
timer->expire_time = current_time
+ (tics * opl_sample_rate) / timer->rate;
}
}
static void WriteRegister(unsigned int reg_num, unsigned int value)
{
switch (reg_num)
{
case OPL_REG_TIMER1:
timer1.value = value;
OPLTimer_CalculateEndTime(&timer1);
break;
case OPL_REG_TIMER2:
timer2.value = value;
OPLTimer_CalculateEndTime(&timer2);
break;
case OPL_REG_TIMER_CTRL:
if (value & 0x80)
{
timer1.enabled = 0;
timer2.enabled = 0;
}
else
{
if ((value & 0x40) == 0)
{
timer1.enabled = (value & 0x01) != 0;
OPLTimer_CalculateEndTime(&timer1);
}
if ((value & 0x20) == 0)
{
timer1.enabled = (value & 0x02) != 0;
OPLTimer_CalculateEndTime(&timer2);
}
}
break;
default:
Chip__WriteReg(&opl_chip, reg_num, value);
break;
}
}
static void OPL_SDL_PortWrite(opl_port_t port, unsigned int value)
{
if (port == OPL_REGISTER_PORT)
{
register_num = value;
}
else if (port == OPL_DATA_PORT)
{
WriteRegister(register_num, value);
}
}
static void OPL_SDL_SetCallback(unsigned int ms,
opl_callback_t callback,
void *data)
{
SDL_LockMutex(callback_queue_mutex);
OPL_Queue_Push(callback_queue, callback, data,
current_time - pause_offset + (ms * mixing_freq) / 1000);
SDL_UnlockMutex(callback_queue_mutex);
}
static void OPL_SDL_ClearCallbacks(void)
{
SDL_LockMutex(callback_queue_mutex);
OPL_Queue_Clear(callback_queue);
SDL_UnlockMutex(callback_queue_mutex);
}
static void OPL_SDL_Lock(void)
{
SDL_LockMutex(callback_mutex);
}
static void OPL_SDL_Unlock(void)
{
SDL_UnlockMutex(callback_mutex);
}
static void OPL_SDL_SetPaused(int paused)
{
opl_sdl_paused = paused;
}
opl_driver_t opl_sdl_driver =
{
"SDL",
OPL_SDL_Init,
OPL_SDL_Shutdown,
OPL_SDL_PortRead,
OPL_SDL_PortWrite,
OPL_SDL_SetCallback,
OPL_SDL_ClearCallbacks,
OPL_SDL_Lock,
OPL_SDL_Unlock,
OPL_SDL_SetPaused
};

251
opl/opl_timer.c Normal file
View file

@ -0,0 +1,251 @@
// 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:
// OPL timer thread.
// Once started using OPL_Timer_StartThread, the thread sleeps,
// waking up to invoke callbacks set using OPL_Timer_SetCallback.
//
//-----------------------------------------------------------------------------
#include "SDL.h"
#include "opl_timer.h"
#include "opl_queue.h"
typedef enum
{
THREAD_STATE_STOPPED,
THREAD_STATE_RUNNING,
THREAD_STATE_STOPPING,
} thread_state_t;
static SDL_Thread *timer_thread = NULL;
static thread_state_t timer_thread_state;
static int current_time;
// If non-zero, callbacks are currently paused.
static int opl_timer_paused;
// Offset in milliseconds to adjust time due to the fact that playback
// was paused.
static unsigned int pause_offset = 0;
// Queue of callbacks waiting to be invoked.
// The callback queue mutex is held while the callback queue structure
// or current_time is being accessed.
static opl_callback_queue_t *callback_queue;
static SDL_mutex *callback_queue_mutex;
// The timer mutex is held while timer callback functions are being
// invoked, so that the calling code can prevent clashes.
static SDL_mutex *timer_mutex;
// Returns true if there is a callback at the head of the queue ready
// to be invoked. Otherwise, next_time is set to the time when the
// timer thread must wake up again to check.
static int CallbackWaiting(unsigned int *next_time)
{
// If paused, just wait in 50ms increments until unpaused.
// Update pause_offset so after we unpause, the callback
// times will be right.
if (opl_timer_paused)
{
*next_time = current_time + 50;
pause_offset += 50;
return 0;
}
// If there are no queued callbacks, sleep for 50ms at a time
// until a callback is added.
if (OPL_Queue_IsEmpty(callback_queue))
{
*next_time = current_time + 50;
return 0;
}
// Read the time of the first callback in the queue.
// If the time for the callback has not yet arrived,
// we must sleep until the callback time.
*next_time = OPL_Queue_Peek(callback_queue) + pause_offset;
return *next_time <= current_time;
}
static unsigned int GetNextTime(void)
{
opl_callback_t callback;
void *callback_data;
unsigned int next_time;
int have_callback;
// Keep running through callbacks until there are none ready to
// run. When we run out of callbacks, next_time will be set.
do
{
SDL_LockMutex(callback_queue_mutex);
// Check if the callback at the head of the list is ready to
// be invoked. If so, pop from the head of the queue.
have_callback = CallbackWaiting(&next_time);
if (have_callback)
{
OPL_Queue_Pop(callback_queue, &callback, &callback_data);
}
SDL_UnlockMutex(callback_queue_mutex);
// Now invoke the callback, if we have one.
// The timer mutex is held while the callback is invoked.
if (have_callback)
{
SDL_LockMutex(timer_mutex);
callback(callback_data);
SDL_UnlockMutex(timer_mutex);
}
} while (have_callback);
return next_time;
}
static int ThreadFunction(void *unused)
{
unsigned int next_time;
unsigned int now;
// Keep running until OPL_Timer_StopThread is called.
while (timer_thread_state == THREAD_STATE_RUNNING)
{
// Get the next time that we must sleep until, and
// wait until that time.
next_time = GetNextTime();
now = SDL_GetTicks();
if (next_time > now)
{
SDL_Delay(next_time - now);
}
// Update the current time.
SDL_LockMutex(callback_queue_mutex);
current_time = next_time;
SDL_UnlockMutex(callback_queue_mutex);
}
timer_thread_state = THREAD_STATE_STOPPED;
return 0;
}
static void InitResources(void)
{
callback_queue = OPL_Queue_Create();
timer_mutex = SDL_CreateMutex();
callback_queue_mutex = SDL_CreateMutex();
}
static void FreeResources(void)
{
OPL_Queue_Destroy(callback_queue);
SDL_DestroyMutex(callback_queue_mutex);
SDL_DestroyMutex(timer_mutex);
}
int OPL_Timer_StartThread(void)
{
InitResources();
timer_thread_state = THREAD_STATE_RUNNING;
current_time = SDL_GetTicks();
opl_timer_paused = 0;
pause_offset = 0;
timer_thread = SDL_CreateThread(ThreadFunction, NULL);
if (timer_thread == NULL)
{
timer_thread_state = THREAD_STATE_STOPPED;
FreeResources();
return 0;
}
return 1;
}
void OPL_Timer_StopThread(void)
{
timer_thread_state = THREAD_STATE_STOPPING;
while (timer_thread_state != THREAD_STATE_STOPPED)
{
SDL_Delay(1);
}
FreeResources();
}
void OPL_Timer_SetCallback(unsigned int ms, opl_callback_t callback, void *data)
{
SDL_LockMutex(callback_queue_mutex);
OPL_Queue_Push(callback_queue, callback, data,
current_time + ms - pause_offset);
SDL_UnlockMutex(callback_queue_mutex);
}
void OPL_Timer_ClearCallbacks(void)
{
SDL_LockMutex(callback_queue_mutex);
OPL_Queue_Clear(callback_queue);
SDL_UnlockMutex(callback_queue_mutex);
}
void OPL_Timer_Lock(void)
{
SDL_LockMutex(timer_mutex);
}
void OPL_Timer_Unlock(void)
{
SDL_UnlockMutex(timer_mutex);
}
void OPL_Timer_SetPaused(int paused)
{
SDL_LockMutex(callback_queue_mutex);
opl_timer_paused = paused;
SDL_UnlockMutex(callback_queue_mutex);
}

42
opl/opl_timer.h Normal file
View file

@ -0,0 +1,42 @@
// 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:
// OPL timer thread.
//
//-----------------------------------------------------------------------------
#ifndef OPL_TIMER_H
#define OPL_TIMER_H
#include "opl.h"
int OPL_Timer_StartThread(void);
void OPL_Timer_StopThread(void);
void OPL_Timer_SetCallback(unsigned int ms,
opl_callback_t callback,
void *data);
void OPL_Timer_ClearCallbacks(void);
void OPL_Timer_Lock(void);
void OPL_Timer_Unlock(void);
void OPL_Timer_SetPaused(int paused);
#endif /* #ifndef OPL_TIMER_H */

172
opl/opl_win32.c Normal file
View file

@ -0,0 +1,172 @@
// 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:
// OPL Win32 native interface.
//
//-----------------------------------------------------------------------------
#include "config.h"
#ifdef _WIN32
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "opl.h"
#include "opl_internal.h"
#include "opl_timer.h"
#include "ioperm_sys.h"
static unsigned int opl_port_base;
// MingW?
#if defined(__GNUC__) && defined(__i386__)
static unsigned int OPL_Win32_PortRead(opl_port_t port)
{
unsigned char result;
__asm__ volatile (
"movl %1, %%edx\n"
"inb %%dx, %%al\n"
"movb %%al, %0"
: "=m" (result)
: "r" (opl_port_base + port)
: "edx", "al", "memory"
);
return result;
}
static void OPL_Win32_PortWrite(opl_port_t port, unsigned int value)
{
__asm__ volatile (
"movl %0, %%edx\n"
"movb %1, %%al\n"
"outb %%al, %%dx"
:
: "r" (opl_port_base + port), "r" ((unsigned char) value)
: "edx", "al"
);
}
// TODO: MSVC version
// #elif defined(_MSC_VER) && defined(_M_IX6) ...
#else
// Not x86, or don't know how to do port R/W on this compiler.
#define NO_PORT_RW
static unsigned int OPL_Win32_PortRead(opl_port_t port)
{
return 0;
}
static void OPL_Win32_PortWrite(opl_port_t port, unsigned int value)
{
}
#endif
static int OPL_Win32_Init(unsigned int port_base)
{
#ifndef NO_PORT_RW
OSVERSIONINFO version_info;
opl_port_base = port_base;
// Check the OS version.
memset(&version_info, 0, sizeof(version_info));
version_info.dwOSVersionInfoSize = sizeof(version_info);
GetVersionEx(&version_info);
// On NT-based systems, we must acquire I/O port permissions
// using the ioperm.sys driver.
if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
// Install driver.
if (!IOperm_InstallDriver())
{
return 0;
}
// Open port range.
if (!IOperm_EnablePortRange(opl_port_base, 2, 1))
{
IOperm_UninstallDriver();
return 0;
}
}
// Start callback thread
if (!OPL_Timer_StartThread())
{
IOperm_UninstallDriver();
return 0;
}
return 1;
#endif
return 0;
}
static void OPL_Win32_Shutdown(void)
{
// Stop callback thread
OPL_Timer_StopThread();
// Unload IOperm library.
IOperm_UninstallDriver();
}
opl_driver_t opl_win32_driver =
{
"Win32",
OPL_Win32_Init,
OPL_Win32_Shutdown,
OPL_Win32_PortRead,
OPL_Win32_PortWrite,
OPL_Timer_SetCallback,
OPL_Timer_ClearCallbacks,
OPL_Timer_Lock,
OPL_Timer_Unlock,
OPL_Timer_SetPaused
};
#endif /* #ifdef _WIN32 */

View file

@ -22,6 +22,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
DOC_FILES = README \
COPYING \
ChangeLog \
INSTALL \
NEWS \
BUGS \
CMDLINE \

View file

@ -6,6 +6,10 @@
include ../config.make
# Build so that the package will work on older versions.
export MACOSX_DEPLOYMENT_TARGET=10.4
STAGING_DIR=staging
DMG=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).dmg

View file

@ -13,6 +13,8 @@ DLL_FILES=$(TOPLEVEL)/src/SDL.dll \
$(TOPLEVEL)/src/SDL_mixer.dll \
$(TOPLEVEL)/src/SDL_net.dll
DOC_FILES += README.OPL
ZIP=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-win32.zip
$(ZIP) : staging

View file

@ -49,9 +49,11 @@ rm -rf $RPM_BUILD_ROOT
%files
%doc %{_mandir}/man5/*
%doc %{_mandir}/man6/*
%doc README
%doc README.OPL
%doc INSTALL
%doc NEWS
%doc AUTHORS
%doc README
%doc COPYING
%doc CMDLINE
%doc BUGS

4
src/.gitignore vendored
View file

@ -3,7 +3,11 @@ Makefile.in
.deps
*.rc
chocolate-doom
chocolate-heretic
chocolate-hexen
chocolate-server
chocolate-setup
*.exe
*.desktop
tags
TAGS

View file

@ -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 $@

View file

@ -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
//

View file

@ -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,

View file

@ -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);

View file

@ -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);
}

View file

@ -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

4
src/doom/.gitignore vendored
View file

@ -1,9 +1,5 @@
Makefile
Makefile.in
.deps
*.rc
chocolate-doom
chocolate-server
*.exe
tags
TAGS

View file

@ -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;
}

View file

@ -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.

View file

@ -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");

View file

@ -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));

View file

@ -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)
{
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])
{
@ -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;

View file

@ -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)
{

View file

@ -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);
}

View file

@ -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)

View file

@ -64,6 +64,7 @@ void P_ArchiveSpecials (void);
void P_UnArchiveSpecials (void);
extern FILE *save_stream;
extern boolean savegame_error;
#endif

View file

@ -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;

View file

@ -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--);
}
//

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}

View file

@ -1,7 +1,6 @@
Makefile
Makefile.in
.deps
*.rc
chocolate-doom
chocolate-server
*.exe
tags
TAGS

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

View file

@ -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();

122
src/heretic/deh_ammo.c Normal file
View file

@ -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,
};

344
src/heretic/deh_frame.c Normal file
View file

@ -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,
};

856
src/heretic/deh_htext.c Normal file
View file

@ -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,
};

186
src/heretic/deh_htic.c Normal file
View file

@ -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]);
}

60
src/heretic/deh_htic.h Normal file
View file

@ -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 */

118
src/heretic/deh_sound.c Normal file
View file

@ -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,
};

150
src/heretic/deh_thing.c Normal file
View file

@ -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,
};

131
src/heretic/deh_weapon.c Normal file
View file

@ -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,
};

View file

@ -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;

View file

@ -24,42 +24,6 @@
// DStrings.h
//---------------------------------------------------------------------------
//
// 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
@ -168,74 +132,6 @@
#define TXT_GAMESAVED "GAME SAVED"
//---------------------------------------------------------------------------
//
// 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
@ -251,26 +147,6 @@
#define AMSTR_MARKEDSPOT "Marked Spot"
#define AMSTR_MARKSCLEARED "All Marks Cleared"
//---------------------------------------------------------------------------
//
// 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 ..."
*/

View file

@ -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.
}
}

View file

@ -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);
}
//==========================================================================

View file

@ -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);
}
}

View file

@ -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

View file

@ -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 */

View file

@ -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));
}

160
src/heretic/p_action.h Normal file
View file

@ -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 */

View file

@ -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;
}

View file

@ -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:

View file

@ -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

View file

@ -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;
//

View file

@ -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));
}
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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));
}
}

View file

@ -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;
}

View file

@ -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');
}
}

View file

@ -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();

View file

@ -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);
}

View file

@ -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

View file

@ -1,7 +1,5 @@
Makefile
Makefile.in
.deps
*.rc
chocolate-doom
chocolate-server
*.exe
tags
TAGS

View file

@ -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++)
{
@ -483,27 +486,6 @@ static void ExecOptionSKILL(char **args, int tag)
autostart = true;
}
//==========================================================================
//
// 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

Some files were not shown because too many files have changed in this diff Show more