summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--INSTALL2
-rw-r--r--Makefile.am9
-rw-r--r--NEWS98
-rw-r--r--TODO21
-rwxr-xr-xautogen.sh2
-rw-r--r--configure.in32
-rw-r--r--data/README7
-rw-r--r--data/doom.icobin2238 -> 36726 bytes
-rw-r--r--data/doom8.icobin0 -> 2238 bytes
-rw-r--r--data/setup.icobin2238 -> 36726 bytes
-rw-r--r--data/setup8.icobin0 -> 2238 bytes
-rw-r--r--man/Makefile.am9
-rw-r--r--pcsound/.gitignore2
-rw-r--r--pkg/.gitignore3
-rw-r--r--pkg/Makefile.am34
-rw-r--r--pkg/config.make.in29
-rw-r--r--pkg/osx/.gitignore7
-rw-r--r--pkg/osx/AppController.h53
-rw-r--r--pkg/osx/AppController.m124
-rw-r--r--pkg/osx/Execute.h31
-rw-r--r--pkg/osx/Execute.m208
-rw-r--r--pkg/osx/GNUmakefile101
-rw-r--r--pkg/osx/IWADController.h54
-rw-r--r--pkg/osx/IWADController.m347
-rw-r--r--pkg/osx/IWADLocation.h44
-rw-r--r--pkg/osx/IWADLocation.m74
-rw-r--r--pkg/osx/Info-gnustep.plist.in36
-rw-r--r--pkg/osx/Info.plist.in60
-rw-r--r--pkg/osx/LauncherManager.h52
-rw-r--r--pkg/osx/LauncherManager.m338
-rw-r--r--pkg/osx/PkgInfo1
-rw-r--r--pkg/osx/Resources/128x128.pngbin0 -> 23029 bytes
-rw-r--r--pkg/osx/Resources/app.icnsbin0 -> 51625 bytes
-rw-r--r--pkg/osx/Resources/app.pngbin0 -> 4597 bytes
-rw-r--r--pkg/osx/Resources/launcher.nib/classes.nib47
-rw-r--r--pkg/osx/Resources/launcher.nib/info.nib23
-rw-r--r--pkg/osx/Resources/launcher.nib/keyedobjects.nibbin0 -> 19616 bytes
-rw-r--r--pkg/osx/Resources/wadfile.icnsbin0 -> 44092 bytes
-rw-r--r--pkg/osx/Resources/wadfile.pngbin0 -> 2249 bytes
-rwxr-xr-xpkg/osx/cp-with-libs100
-rw-r--r--pkg/osx/main.m32
-rw-r--r--pkg/win32/GNUmakefile34
-rw-r--r--pkg/win32/GNUmakefile.am37
-rw-r--r--pkg/wince/GNUmakefile (renamed from pkg/wince/GNUmakefile.am)15
-rw-r--r--rpm.spec.in59
-rw-r--r--src/.gitignore2
-rw-r--r--src/Makefile.am2
-rw-r--r--src/d_iwad.c91
-rw-r--r--src/doom/.gitignore2
-rw-r--r--src/doom/g_game.c14
-rw-r--r--src/doom/hu_stuff.c30
-rw-r--r--src/doom/p_map.c21
-rw-r--r--src/doom/p_setup.c27
-rw-r--r--src/doom/p_sight.c10
-rw-r--r--src/doom/st_stuff.c18
-rw-r--r--src/i_video.c1
-rw-r--r--src/mus2mid.c1019
-rw-r--r--src/resource.rc.in2
-rw-r--r--src/setup/.gitignore7
-rw-r--r--src/setup/Makefile.am7
-rw-r--r--src/setup/execute.c33
-rw-r--r--textscreen/.gitignore2
-rw-r--r--textscreen/examples/.gitignore2
-rw-r--r--textscreen/txt_sdl.c8
-rw-r--r--wince/.gitignore5
-rw-r--r--wince/Makefile.am1
67 files changed, 2792 insertions, 640 deletions
diff --git a/.gitignore b/.gitignore
index c4da3d0e..34652d0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,9 +10,12 @@ config.log
config.status
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
diff --git a/INSTALL b/INSTALL
index cb076992..80df9361 100644
--- a/INSTALL
+++ b/INSTALL
@@ -23,7 +23,7 @@ Building Chocolate Doom
On a Unix system, follow the standard instructions for installing an
autotools-based package:
- 1. Run './configure' to initialise the package.
+ 1. Run './configure' to initialize the package.
2. Run 'make' to compile the package.
3. Run 'make install' to install the package.
diff --git a/Makefile.am b/Makefile.am
index 15ad2252..e331d204 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,9 +32,12 @@ CODEBLOCKS_FILES= \
codeblocks/setup-res.rc
DATA_FILES= \
+ data/README \
data/doom.ico \
+ data/doom8.ico \
data/doom.png \
data/setup.ico \
+ data/setup8.ico \
data/setup.png \
data/convert-icon
@@ -43,11 +46,13 @@ EXTRA_DIST= \
$(MSVC_FILES) \
$(CODEBLOCKS_FILES) \
$(DATA_FILES) \
+ .lvimrc \
config.h \
CMDLINE \
HACKING \
TODO \
- BUGS
+ BUGS \
+ rpm.spec
MAINTAINERCLEANFILES = $(AUX_DIST_GEN)
@@ -57,6 +62,8 @@ DIST_SUBDIRS=pkg $(SUBDIRS)
if HAVE_PYTHON
+noinst_DATA=CMDLINE
+
CMDLINE : src/
./man/docgen -p man/CMDLINE.template src/ > $@
diff --git a/NEWS b/NEWS
index 2d6db773..ac12bded 100644
--- a/NEWS
+++ b/NEWS
@@ -1,48 +1,96 @@
...
* Chocolate Doom now runs on Windows Mobile/Windows CE!
- * It is possible to rebind most/all of the keys that control
- the menu, shortcuts, automap and weapon switching. The
- main reason for this is to support the Windows CE port
- and other platforms where a full keyboard may not be present.
- * Memory-mapped WAD I/O is disabled by default, as it caused
- various issues, including a slowdown/crash with Plutonia 2
- MAP23. It can be explicitly re-enabled using the '-mmap'
- command line parameter.
+ * It is possible to rebind most/all of the keys that control the
+ menu, shortcuts, automap and weapon switching. The main
+ reason for this is to support the Windows CE port and other
+ platforms where a full keyboard may not be present.
+ * Chocolate Doom now includes a proper Mac OS X package; it is
+ no longer necessary to compile binaries for this system by
+ hand. The package includes a simple graphical launcher
+ program and can be installed simply by dragging the "Chocolate
+ Doom" icon to the Applications folder. (thanks to Rikard Lang
+ for extensive testing and feedback)
* The video mode auto-adjust code will automatically choose
windowed mode if no fullscreen video modes are available.
- * The zone memory size is automatically reduced on systems
- with a small amount of memory.
- * There is now a second, small textscreen font, so that the
- ENDOOM screen and setup tool can be used on low resolution
- devices (eg. PDAs/embedded devices)
- * The textscreen library now has a scrollable pane widget.
- * Doxygen documentation was added for the textscreen library.
- * The "join game" window in the setup tool now has an option
- to automatically join a game on the local network.
+ * The zone memory size is automatically reduced on systems with
+ a small amount of memory.
+ * The "join game" window in the setup tool now has an option to
+ automatically join a game on the local network.
+ * Chocolate Doom includes some initial hacks for compiling under
+ SDL 1.3.
+ * Recent versions of SDL_mixer include rewritten MIDI code on Mac
+ OS X. If you are using a version of SDL_mixer with the new
+ code, music will now be enabled by default.
+ * Windows Vista and Windows 7 no longer prompt for elevated
+ privileges when running the setup tool (thanks hobbs and
+ MikeRS).
+ * The Windows binaries now have better looking icons (thanks
+ MikeRS).
+ * Magic values specified using the -spechit command line
+ parameter can now be hexadecimal.
+ * DOOMWADDIR/DOOMWADPATH can now specify the complete path to
+ IWAD files, rather than the path to the directory that contains
+ them.
+ * When recording shorttics demos, errors caused by the reduced
+ turning resolution are carried forward, possibly making turning
+ smoother.
Compatibility:
* The A_BossDeath behavior in v1.9 emulation mode was fixed
(thanks entryway)
+ * The "loading" disk icon is drawn more like how it is drawn in
+ Vanilla Doom, also fixing a bug with chook3.wad.
+ * Desync on 64-bit systems with ep1-0500.lmp has (at long last)
+ been fixed (thanks exp(x)).
+ * Donut overrun emulation code imported from Prboom+ (thanks
+ entryway).
+ * The correct level name should now be shown in the automap for
+ pl2.wad MAP33 (thanks Janizdreg).
+ * In Chex Quest, the green radiation suit colormap is now used
+ instead of the red colormaps normally used when taking damage
+ or using the berserk pack. This matches Vanilla chex.exe
+ behavior (thanks Fuzztooth).
+ * Impassible glass now displays and works the same as in Vanilla,
+ fixing wads such as OTTAWAU.WAD (thanks Never_Again).
Bugs fixed:
+ * Memory-mapped WAD I/O is disabled by default, as it caused
+ various issues, including a slowdown/crash with Plutonia 2
+ MAP23. It can be explicitly re-enabled using the '-mmap'
+ command line parameter.
* Crash when saving games due to the ~/.chocolate-doom/savegames
directory not being created (thanks to everyone who reported
this).
- * Chocolate Doom will now under Win95/98, as the
+ * Chocolate Doom will now run under Win95/98, as the
SetProcessAffinityMask function is looked up dynamically.
* Compilation under Linux with older versions of libc will now
work (the semantics for sched_setaffinity were different in
older versions)
* Sound clipping when using libsamplerate was improved (thanks
David Flater)
- * The audio buffer size is now calculated based on the sample rate,
- so there is not a noticeable delay when using a lower sample
- rate.
- * The manpage documentation for the DOOMWADPATH variable was fixed
- (thanks MikeRS).
- * Compilation with FEATURE_MULTIPLAYER and FEATURE_SOUND disabled
- was fixed.
+ * The audio buffer size is now calculated based on the sample
+ rate, so there is not a noticeable delay when using a lower
+ sample rate.
+ * The manpage documentation for the DOOMWADPATH variable was
+ fixed (thanks MikeRS).
+ * Compilation with FEATURE_MULTIPLAYER and FEATURE_SOUND
+ disabled was fixed.
+ * Fixed crash when using the donut special type and the joining
+ linedef is one sided (thanks Alexander Waldmann).
+ * Key settings in a configuration file that are out of range
+ do not cause a crash (thanks entryway).
+ * Fix ear-piercing whistle when playing the MAP05 MIDI music
+ using timidity with EAWPATS (thanks entryway / HackNeyed).
+
+ libtextscreen:
+ * There is now a second, small textscreen font, so that the
+ ENDOOM screen and setup tool can be used on low resolution
+ devices (eg. PDAs/embedded devices)
+ * The textscreen library now has a scrollable pane widget. Thanks
+ to LionsPhil for contributing code to scroll up and down using
+ the keyboard.
+ * Doxygen documentation was added for the textscreen library.
1.2.1 (2008-12-10):
diff --git a/TODO b/TODO
index cd4006a3..b0acb8d3 100644
--- a/TODO
+++ b/TODO
@@ -1,17 +1,22 @@
+Currently in progress:
+
+* OPL MIDI playback (see: opl-branch)
+* Heretic/Hexen support (see: raven-branch)
+* Strife support (see: strife-branch)
+
To do:
-* Install packages:
- - Debian/Ubuntu .deb packages, Fedora .rpm packages.
- - Windows NSIS installer.
- - MacOS X .dmg packages (should be universal binaries!)
+* Demo hashes for regression testing of this and other ports.
* File selector for chocolate-setup, so that WADs can be selected from
a browser, instead of simply typing the filenames.
* Multiplayer:
- Master server for locating servers automatically - makes setting up
public servers easier.
+ - Use UPnP to automatically configure port forwarding for NATted
+ networks.
- Incorporate local LAN search into setup interface.
- Multiplayer options and configuration file (server name, etc)
-* Improve multiplayer startup:
+* Improve multiplayer startup:
- Select an IWAD automatically from the server's game type rather than
all players having to specify -iwad.
- Send list of WADs to load instead of all clients having to specify -file.
@@ -20,16 +25,14 @@ To do:
- Test on and fix for architectures where ((-2) >> 1) != -1
- Use size-specific types (eg. int32_t instead of int)
- Don't make structure packing assumptions when loading levels.
-* Port to every OS and architecture under the sun
+ - Port to every OS and architecture under the sun
Crazy pie in the sky ideas:
* Automatic WAD installer - download and run TCs from a list automatically
(automating the current "instructions on wiki" system).
-* Textscreen interface to the Compet-N database: menu driven system to
+* Textscreen interface to the Compet-N database: menu driven system to
automatically download and play speedruns.
* DWANGO-like interface for finding players and setting up games.
-* Demo hashes for regression testing of this and other ports.
-* OPL emulation
* Video capture mode?
diff --git a/autogen.sh b/autogen.sh
index ee0e377d..851603c6 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -8,5 +8,5 @@ automake -a -c
autoconf
automake
-./configure $@
+./configure "$@"
diff --git a/configure.in b/configure.in
index 0f4b48a0..e3287d00 100644
--- a/configure.in
+++ b/configure.in
@@ -1,5 +1,11 @@
AC_INIT(Chocolate Doom, 1.2.1, fraggle@gmail.com, chocolate-doom)
+PACKAGE_SHORTDESC="Conservative Doom source port"
+PACKAGE_COPYRIGHT="Copyright (C) 1993-2010"
+PACKAGE_LICENSE="GNU General Public License, version 2"
+PACKAGE_MAINTAINER="Simon Howard"
+PACKAGE_URL="http://www.chocolate-doom.org/"
+
AC_CONFIG_AUX_DIR(autotools)
orig_CFLAGS="$CFLAGS"
@@ -120,27 +126,35 @@ AC_SUBST(SDLNET_LIBS)
AC_SUBST(ac_aux_dir)
+AC_SUBST(PACKAGE_SHORTDESC)
+AC_SUBST(PACKAGE_COPYRIGHT)
+AC_SUBST(PACKAGE_LICENSE)
+AC_SUBST(PACKAGE_MAINTAINER)
+AC_SUBST(PACKAGE_URL)
+
dnl Shut up the datarootdir warnings.
AC_DEFUN([AC_DATAROOTDIR_CHECKED])
AC_OUTPUT([
Makefile
-wince/Makefile
-textscreen/Makefile
-textscreen/examples/Makefile
man/Makefile
+pcsound/Makefile
+pkg/Makefile
+pkg/config.make
+pkg/osx/Info-gnustep.plist
+pkg/osx/Info.plist
+rpm.spec
src/Makefile
+src/doom-screensaver.desktop
src/doom/Makefile
src/heretic/Makefile
src/hexen/Makefile
-src/setup/Makefile
-pcsound/Makefile
-pkg/Makefile
-pkg/wince/GNUmakefile
-pkg/win32/GNUmakefile
src/resource.rc
src/setup-res.rc
+src/setup/Makefile
src/setup/setup-manifest.xml
-src/doom-screensaver.desktop
+textscreen/Makefile
+textscreen/examples/Makefile
+wince/Makefile
])
diff --git a/data/README b/data/README
index 8b927335..82fac17e 100644
--- a/data/README
+++ b/data/README
@@ -3,3 +3,10 @@ The Chocolate Doom icon is based on an image by Chris Metcalf
http://www.flickr.com/photos/laffy4k/448920776/
+The "foo8.ico" files are 8-bit depth only, while the "foo.ico" files
+contain full 32-bit versions, scaled to different sizes and with proper
+alpha masks (as well as the 8-bit versions). The 8-bit versions are
+used when setting the icon within SDL, as SDL under Windows displays
+full color icons in a very poor quality. The full-color versions are
+used in the resource files.
+
diff --git a/data/doom.ico b/data/doom.ico
index f55ff28f..025cb698 100644
--- a/data/doom.ico
+++ b/data/doom.ico
Binary files differ
diff --git a/data/doom8.ico b/data/doom8.ico
new file mode 100644
index 00000000..f55ff28f
--- /dev/null
+++ b/data/doom8.ico
Binary files differ
diff --git a/data/setup.ico b/data/setup.ico
index 6d734a11..dae4e5ec 100644
--- a/data/setup.ico
+++ b/data/setup.ico
Binary files differ
diff --git a/data/setup8.ico b/data/setup8.ico
new file mode 100644
index 00000000..6d734a11
--- /dev/null
+++ b/data/setup8.ico
Binary files differ
diff --git a/man/Makefile.am b/man/Makefile.am
index d3c90f7e..698c0862 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -5,9 +5,9 @@ if HAVE_PYTHON
man_MANS=chocolate-doom.6 \
chocolate-server.6 \
- chocolate-setup.6 \
- default.cfg.5 \
- $(PACKAGE).cfg.5
+ chocolate-setup.6 \
+ default.cfg.5 \
+ $(PACKAGE).cfg.5
chocolate-doom.6: ../src $(MANPAGE_GEN_FILES)
./docgen -m manpage.template ../src > $@
@@ -21,5 +21,6 @@ $(PACKAGE).cfg.5: ../src extra.cfg.template
endif
EXTRA_DIST = $(man_MANS) $(MANPAGE_GEN_FILES) \
- wikipages
+ wikipages \
+ CMDLINE.template
diff --git a/pcsound/.gitignore b/pcsound/.gitignore
index 9889f6d5..022c663e 100644
--- a/pcsound/.gitignore
+++ b/pcsound/.gitignore
@@ -3,4 +3,6 @@ Makefile
.deps
libpcsound.a
*.rc
+tags
+TAGS
diff --git a/pkg/.gitignore b/pkg/.gitignore
new file mode 100644
index 00000000..a1dd1cde
--- /dev/null
+++ b/pkg/.gitignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+config.make
diff --git a/pkg/Makefile.am b/pkg/Makefile.am
index 66cb9ba0..63da8f53 100644
--- a/pkg/Makefile.am
+++ b/pkg/Makefile.am
@@ -1,3 +1,35 @@
-DIST_SUBDIRS=wince win32
+OSX_FILES= \
+osx/Resources/128x128.png \
+osx/Resources/app.icns \
+osx/Resources/app.png \
+osx/Resources/wadfile.icns \
+osx/Resources/wadfile.png \
+osx/Resources/launcher.nib/classes.nib \
+osx/Resources/launcher.nib/info.nib \
+osx/Resources/launcher.nib/keyedobjects.nib \
+osx/GNUmakefile \
+osx/Info.plist.in osx/Info-gnustep.plist.in \
+osx/PkgInfo \
+osx/cp-with-libs \
+osx/main.m \
+osx/AppController.m osx/AppController.h \
+osx/Execute.m osx/Execute.h \
+osx/IWADController.m osx/IWADController.h \
+osx/IWADLocation.m osx/IWADLocation.h \
+osx/LauncherManager.m osx/LauncherManager.h
+
+WINCE_FILES= \
+wince/GNUmakefile \
+wince/common.py \
+wince/doom-cab.cfg \
+wince/heretic-cab.cfg \
+wince/hexen-cab.cfg \
+wince/wince-cabgen
+
+WIN32_FILES= \
+win32/GNUmakefile \
+win32/README
+
+EXTRA_DIST=$(OSX_FILES) $(WINCE_FILES) $(WIN32_FILES)
diff --git a/pkg/config.make.in b/pkg/config.make.in
new file mode 100644
index 00000000..b8a1dbe5
--- /dev/null
+++ b/pkg/config.make.in
@@ -0,0 +1,29 @@
+# Shared file included by the makefiles used to build packages.
+# This contains various information needed by the makefiles,
+# and is autogenerated by configure to include various
+# necessary details.
+
+# Tools needed:
+
+CC = @CC@
+STRIP = @STRIP@
+
+# Package name and version number:
+
+PROGRAM_PREFIX = @PROGRAM_PREFIX@
+PACKAGE = @PACKAGE@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+
+# Documentation files to distribute with packages.
+
+DOC_FILES = README \
+ COPYING \
+ ChangeLog \
+ NEWS \
+ BUGS \
+ CMDLINE \
+ TODO
+
diff --git a/pkg/osx/.gitignore b/pkg/osx/.gitignore
new file mode 100644
index 00000000..ca1a7908
--- /dev/null
+++ b/pkg/osx/.gitignore
@@ -0,0 +1,7 @@
+Info.plist
+Info-gnustep.plist
+launcher
+*.o
+*.d
+*.dmg
+staging
diff --git a/pkg/osx/AppController.h b/pkg/osx/AppController.h
new file mode 100644
index 00000000..88b59043
--- /dev/null
+++ b/pkg/osx/AppController.h
@@ -0,0 +1,53 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_APPCONTROLLER_H
+#define LAUNCHER_APPCONTROLLER_H
+
+#include <AppKit/AppKit.h>
+
+#include "LauncherManager.h"
+
+@interface AppController : NSObject
+{
+ LauncherManager *launcherManager;
+ BOOL filesAdded;
+}
+
++ (void)initialize;
+
+- (id)init;
+- (void)dealloc;
+
+- (void)awakeFromNib;
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotif;
+- (BOOL)applicationShouldTerminate:(id)sender;
+- (void)applicationWillTerminate:(NSNotification *)aNotif;
+- (BOOL)application:(NSApplication *)application openFile:(NSString *)fileName;
+
+- (void)showPrefPanel:(id)sender;
+
+@end
+
+#endif
+
diff --git a/pkg/osx/AppController.m b/pkg/osx/AppController.m
new file mode 100644
index 00000000..a26a7c9e
--- /dev/null
+++ b/pkg/osx/AppController.m
@@ -0,0 +1,124 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#include "AppController.h"
+
+#include "config.h"
+
+@implementation AppController
+
++ (void)initialize
+{
+ NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
+
+ /*
+ * Register your app's defaults here by adding objects to the
+ * dictionary, eg
+ *
+ * [defaults setObject:anObject forKey:keyForThatObject];
+ *
+ */
+
+ [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
+ [[NSUserDefaults standardUserDefaults] synchronize];
+}
+
+- (id)init
+{
+ if ((self = [super init]))
+ {
+ }
+
+ self->filesAdded = NO;
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [super dealloc];
+}
+
+- (void)awakeFromNib
+{
+ [[NSApp mainMenu] setTitle:@PACKAGE_NAME];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotif
+{
+// Uncomment if your application is Renaissance-based
+// [NSBundle loadGSMarkupNamed:@"Main" owner:self];
+}
+
+- (BOOL)applicationShouldTerminate:(id)sender
+{
+ return YES;
+}
+
+- (void)applicationWillTerminate:(NSNotification *)aNotif
+{
+}
+
+- (BOOL) application:(NSApplication *) application
+ openFile:(NSString *) fileName
+{
+ NSString *extension;
+
+ // If this is the first file added, clear out the existing
+ // command line. This allows us to select multiple files
+ // in the finder and open them all together (for TCs, etc).
+
+ if (!self->filesAdded)
+ {
+ [self->launcherManager clearCommandLine];
+ }
+
+ // Add file with appropriate command line option based on extension:
+
+ extension = [fileName pathExtension];
+
+ if (![extension caseInsensitiveCompare: @"wad"])
+ {
+ [self->launcherManager addFileToCommandLine: fileName
+ forArgument: @"-merge"];
+ }
+ else if (![extension caseInsensitiveCompare: @"deh"])
+ {
+ [self->launcherManager addFileToCommandLine: fileName
+ forArgument: @"-deh"];
+ }
+ else
+ {
+ return NO;
+ }
+
+ self->filesAdded = YES;
+
+ return YES;
+}
+
+- (void)showPrefPanel:(id)sender
+{
+}
+
+@end
+
diff --git a/pkg/osx/Execute.h b/pkg/osx/Execute.h
new file mode 100644
index 00000000..2098be8a
--- /dev/null
+++ b/pkg/osx/Execute.h
@@ -0,0 +1,31 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_EXECUTE_H
+#define LAUNCHER_EXECUTE_H
+
+void SetProgramLocation(const char *path);
+void ExecuteProgram(const char *executable, const char *iwad, const char *args);
+void OpenTerminalWindow(const char *doomwadpath);
+
+#endif /* #ifndef LAUNCHER_EXECUTE_H */
+
diff --git a/pkg/osx/Execute.m b/pkg/osx/Execute.m
new file mode 100644
index 00000000..608443e2
--- /dev/null
+++ b/pkg/osx/Execute.m
@@ -0,0 +1,208 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <AppKit/AppKit.h>
+
+#include "config.h"
+
+#define RESPONSE_FILE "/tmp/launcher.rsp"
+#define TEMP_SCRIPT "/tmp/tempscript.sh"
+
+static char *executable_path;
+
+// Called on startup to save the location of the launcher program
+// (within a package, other executables should be in the same directory)
+
+void SetProgramLocation(const char *path)
+{
+ char *p;
+
+ executable_path = strdup(path);
+
+ p = strrchr(executable_path, '/');
+ *p = '\0';
+}
+
+// Write out the response file containing command line arguments.
+
+static void WriteResponseFile(const char *iwad, const char *args)
+{
+ FILE *fstream;
+
+ fstream = fopen(RESPONSE_FILE, "w");
+
+ if (iwad != NULL)
+ {
+ fprintf(fstream, "-iwad \"%s\"", iwad);
+ }
+
+ if (args != NULL)
+ {
+ fprintf(fstream, "%s", args);
+ }
+
+ fclose(fstream);
+}
+
+static void DoExec(const char *executable, const char *iwad, const char *args)
+{
+ char *argv[3];
+
+ argv[0] = malloc(strlen(executable_path) + strlen(executable) + 3);
+ sprintf(argv[0], "%s/%s", executable_path, executable);
+
+ if (iwad != NULL || args != NULL)
+ {
+ WriteResponseFile(iwad, args);
+
+ argv[1] = "@" RESPONSE_FILE;
+ argv[2] = NULL;
+ }
+ else
+ {
+ argv[1] = NULL;
+ }
+
+ execv(argv[0], argv);
+ exit(-1);
+}
+
+// Execute the specified executable contained in the same directory
+// as the launcher, with the specified arguments.
+
+void ExecuteProgram(const char *executable, const char *iwad, const char *args)
+{
+ pid_t childpid;
+ char *homedir;
+
+ childpid = fork();
+
+ if (childpid == 0)
+ {
+ signal(SIGCHLD, SIG_DFL);
+
+ // Change directory to home dir before launch, so that any demos
+ // are saved somewhere sensible.
+
+ homedir = getenv("HOME");
+
+ if (homedir != NULL)
+ {
+ chdir(homedir);
+ }
+
+ DoExec(executable, iwad, args);
+ }
+ else
+ {
+ signal(SIGCHLD, SIG_IGN);
+ }
+}
+
+// Write a sequence of commands that will display the specified message
+// via shell commands.
+
+static void WriteMessage(FILE *script, char *msg)
+{
+ char *p;
+
+ fprintf(script, "echo \"");
+
+ for (p=msg; *p != '\0'; ++p)
+ {
+ // Start new line?
+
+ if (*p == '\n')
+ {
+ fprintf(script, "\"\necho \"");
+ continue;
+ }
+
+ // Escaped character?
+
+ if (*p == '\\' || *p == '\"')
+ {
+ fprintf(script, "\\");
+ }
+
+ fprintf(script, "%c", *p);
+ }
+
+ fprintf(script, "\"\n");
+}
+
+// Open a terminal window with the PATH set appropriately, and DOOMWADPATH
+// set to the specified value.
+
+void OpenTerminalWindow(const char *doomwadpath)
+{
+ FILE *stream;
+
+ // Generate a shell script that sets the PATH to include the location
+ // where the Doom binaries are, and DOOMWADPATH to include the
+ // IWAD files that have been configured in the launcher interface.
+ // The script then deletes itself and starts a shell.
+
+ stream = fopen(TEMP_SCRIPT, "w");
+
+ fprintf(stream, "#!/bin/sh\n");
+ //fprintf(stream, "set -x\n");
+ fprintf(stream, "PATH=\"%s:$PATH\"\n", executable_path);
+ fprintf(stream, "DOOMWADPATH=\"%s\"\n", doomwadpath);
+ fprintf(stream, "export DOOMWADPATH\n");
+ fprintf(stream, "rm -f \"%s\"\n", TEMP_SCRIPT);
+
+ // Display a useful message:
+
+ fprintf(stream, "clear\n");
+ WriteMessage(stream,
+ "\n"
+ "This command line has the PATH variable configured so that you may\n"
+ "launch the game with whatever parameters you desire.\n"
+ "\n"
+ "For example:\n"
+ "\n"
+ " " PACKAGE_TARNAME " -iwad doom2.wad -file sid.wad -warp 1\n"
+ "\n"
+ "Type 'exit' to exit.\n");
+
+ fprintf(stream, "exec $SHELL\n");
+ fprintf(stream, "\n");
+
+ fclose(stream);
+
+ chmod(TEMP_SCRIPT, 0755);
+
+ // Tell the terminal to open a window to run the script.
+
+ [[NSWorkspace sharedWorkspace] openFile: @TEMP_SCRIPT
+ withApplication: @"Terminal"];
+}
+
diff --git a/pkg/osx/GNUmakefile b/pkg/osx/GNUmakefile
new file mode 100644
index 00000000..d119efa1
--- /dev/null
+++ b/pkg/osx/GNUmakefile
@@ -0,0 +1,101 @@
+
+# Makefile for building the OS X launcher program and DMG package.
+# It is also possible to build and run the launcher under Unix
+# systems using GNUstep, although this is only here for development
+# and debugging purposes.
+
+include ../config.make
+
+STAGING_DIR=staging
+DMG=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).dmg
+
+TOPLEVEL=../..
+TOPLEVEL_DOCS=$(patsubst %,../../%,$(DOC_FILES))
+
+ifndef GNUSTEP_MAKEFILES
+
+# DMG file containing package:
+
+$(DMG) : $(STAGING_DIR)
+ rm -f $@
+ hdiutil create -volname "$(PACKAGE_STRING)" -srcdir $(STAGING_DIR) $@
+
+endif
+
+# Staging dir build for package:
+
+APP_DIR=$(STAGING_DIR)/$(PACKAGE_NAME).app
+
+# OS X and GNUstep apps have a slightly different internal structure:
+# OS X apps have their files within a containing "Contents" directory
+# that does not exist in GNUstep apps. Similarly, the binaries are
+# installed at the top level, rather than in a "MacOS" directory.
+# Finally, we must install a different Info.plist file.
+
+ifdef GNUSTEP_MAKEFILES
+APP_TOP_DIR=$(APP_DIR)
+APP_BIN_DIR=$(APP_DIR)
+SRC_INFO_PLIST=Info-gnustep.plist
+else
+APP_TOP_DIR=$(APP_DIR)/Contents
+APP_BIN_DIR=$(APP_DIR)/Contents/MacOS
+SRC_INFO_PLIST=Info.plist
+endif
+
+$(STAGING_DIR): launcher $(TOPLEVEL_DOCS)
+ rm -rf $(STAGING_DIR)
+ mkdir $(STAGING_DIR)
+
+ cp $(TOPLEVEL_DOCS) "$(STAGING_DIR)"
+
+ mkdir -p "$(APP_TOP_DIR)"
+ cp -R Resources "$(APP_TOP_DIR)"
+ cp PkgInfo "$(APP_TOP_DIR)"
+ cp $(SRC_INFO_PLIST) "$(APP_TOP_DIR)"
+
+ mkdir -p "$(APP_BIN_DIR)"
+
+ cp launcher "$(APP_BIN_DIR)"
+ $(STRIP) "$(APP_BIN_DIR)/launcher"
+
+ ./cp-with-libs $(TOPLEVEL)/src/$(PACKAGE_TARNAME) "$(APP_BIN_DIR)"
+ $(STRIP) "$(APP_BIN_DIR)/$(PACKAGE_TARNAME)"
+ ./cp-with-libs $(TOPLEVEL)/setup/chocolate-setup "$(APP_BIN_DIR)"
+ $(STRIP) "$(APP_BIN_DIR)/chocolate-setup"
+
+ find $(STAGING_DIR) -name .svn -delete -exec rm -rf {} \; || true
+
+clean : launcher_clean
+ rm -f $(DMG)
+ rm -rf $(STAGING_DIR)
+
+# Launcher build:
+
+CFLAGS = -Wall -I$(TOPLEVEL)
+
+# Are we building using gs_make?
+
+ifdef GNUSTEP_MAKEFILES
+CFLAGS += $(shell gnustep-config --objc-flags)
+LDFLAGS = $(shell gnustep-config --gui-libs)
+else
+LDFLAGS = -framework Cocoa
+endif
+
+LAUNCHER_OBJS= \
+ AppController.o \
+ Execute.o \
+ IWADController.o \
+ IWADLocation.o \
+ LauncherManager.o \
+ main.o
+
+launcher : $(LAUNCHER_OBJS)
+ $(CC) $(LDFLAGS) $(LAUNCHER_OBJS) -o $@
+
+%.o : %.m
+ $(CC) -c $(CFLAGS) $^ -o $@
+
+launcher_clean :
+ rm -f $(LAUNCHER_OBJS) launcher
+
diff --git a/pkg/osx/IWADController.h b/pkg/osx/IWADController.h
new file mode 100644
index 00000000..90f44667
--- /dev/null
+++ b/pkg/osx/IWADController.h
@@ -0,0 +1,54 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_IWADCONTROLLER_H
+#define LAUNCHER_IWADCONTROLLER_H
+
+#include <AppKit/AppKit.h>
+#include <AppKit/NSNibLoading.h>
+
+@interface IWADController : NSObject
+{
+ id iwadSelector;
+ id configWindow;
+
+ id chex;
+ id doom1;
+ id doom2;
+ id plutonia;
+ id tnt;
+}
+
+- (void) closeConfigWindow: (id)sender;
+- (void) openConfigWindow: (id)sender;
+- (NSString *) getIWADLocation;
+- (void) awakeFromNib;
+- (BOOL) setDropdownList;
+- (void) setDropdownSelection;
+- (void) saveConfig;
+- (char *) doomWadPath;
+- (void) setEnvironment;
+
+@end
+
+#endif /* #ifndef LAUNCHER_IWADCONTROLLER_H */
+
diff --git a/pkg/osx/IWADController.m b/pkg/osx/IWADController.m
new file mode 100644
index 00000000..3c596850
--- /dev/null
+++ b/pkg/osx/IWADController.m
@@ -0,0 +1,347 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+#include <string.h>
+#include <AppKit/AppKit.h>
+#include "IWADController.h"
+#include "IWADLocation.h"
+
+typedef enum
+{
+ IWAD_DOOM1,
+ IWAD_DOOM2,
+ IWAD_TNT,
+ IWAD_PLUTONIA,
+ IWAD_CHEX,
+ NUM_IWAD_TYPES
+} IWAD;
+
+static NSString *IWADLabels[NUM_IWAD_TYPES] =
+{
+ @"Doom",
+ @"Doom II: Hell on Earth",
+ @"Final Doom: TNT: Evilution",
+ @"Final Doom: Plutonia Experiment",
+ @"Chex Quest"
+};
+
+static NSString *IWADFilenames[NUM_IWAD_TYPES + 1] =
+{
+ @"doom.wad",
+ @"doom2.wad",
+ @"tnt.wad",
+ @"plutonia.wad",
+ @"chex.wad",
+ @"undefined"
+};
+
+@implementation IWADController
+
+- (void) getIWADList: (IWADLocation **) iwadList
+{
+ iwadList[IWAD_DOOM1] = self->doom1;
+ iwadList[IWAD_DOOM2] = self->doom2;
+ iwadList[IWAD_TNT] = self->tnt;
+ iwadList[IWAD_PLUTONIA] = self->plutonia;
+ iwadList[IWAD_CHEX] = self->chex;
+}
+
+- (IWAD) getSelectedIWAD
+{
+ unsigned int i;
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ if ([self->iwadSelector titleOfSelectedItem] == IWADLabels[i])
+ {
+ return i;
+ }
+ }
+
+ return NUM_IWAD_TYPES;
+}
+
+// Get the location of the selected IWAD.
+
+- (NSString *) getIWADLocation
+{
+ IWAD selectedIWAD;
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+
+ selectedIWAD = [self getSelectedIWAD];
+
+ if (selectedIWAD == NUM_IWAD_TYPES)
+ {
+ return nil;
+ }
+ else
+ {
+ [self getIWADList: iwadList];
+
+ return [iwadList[selectedIWAD] getLocation];
+ }
+}
+
+- (void) setIWADConfig
+{
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+ NSUserDefaults *defaults;
+ NSString *key;
+ NSString *value;
+ unsigned int i;
+
+ [self getIWADList: iwadList];
+
+ // Load IWAD filename paths
+
+ defaults = [NSUserDefaults standardUserDefaults];
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ key = IWADFilenames[i];
+ value = [defaults stringForKey:key];
+
+ if (value != nil)
+ {
+ [iwadList[i] setLocation:value];
+ }
+ }
+}
+
+// On startup, set the selected item in the IWAD dropdown
+
+- (void) setDropdownSelection
+{
+ NSUserDefaults *defaults;
+ NSString *selected;
+ unsigned int i;
+
+ defaults = [NSUserDefaults standardUserDefaults];
+ selected = [defaults stringForKey: @"selected_iwad"];
+
+ if (selected == nil)
+ {
+ return;
+ }
+
+ // Find this IWAD in the filenames list, and select it.
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ if ([selected isEqualToString:IWADFilenames[i]])
+ {
+ [self->iwadSelector selectItemWithTitle:IWADLabels[i]];
+ break;
+ }
+ }
+}
+
+// Set the dropdown list to include an entry for each IWAD that has
+// been configured. Returns true if at least one IWAD is configured.
+
+- (BOOL) setDropdownList
+{
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+ BOOL have_wads;
+ id location;
+ unsigned int i;
+ unsigned int enabled_wads;
+
+ // Build the new list.
+
+ [self getIWADList: iwadList];
+ [self->iwadSelector removeAllItems];
+
+ enabled_wads = 0;
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ location = [iwadList[i] getLocation];
+
+ if (location != nil && [location length] > 0)
+ {
+ [self->iwadSelector addItemWithTitle: IWADLabels[i]];
+ ++enabled_wads;
+ }
+ }
+
+ // Enable/disable the dropdown depending on whether there
+ // were any configured IWADs.
+
+ have_wads = enabled_wads > 0;
+ [self->iwadSelector setEnabled: have_wads];
+
+ // Restore the old selection.
+
+ [self setDropdownSelection];
+
+ return have_wads;
+}
+
+- (void) saveConfig
+{
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+ IWAD selectedIWAD;
+ NSUserDefaults *defaults;
+ NSString *key;
+ NSString *value;
+ unsigned int i;
+
+ [self getIWADList: iwadList];
+
+ // Store all IWAD locations to user defaults.
+
+ defaults = [NSUserDefaults standardUserDefaults];
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ key = IWADFilenames[i];
+ value = [iwadList[i] getLocation];
+
+ [defaults setObject:value forKey:key];
+ }
+
+ // Save currently selected IWAD.
+
+ selectedIWAD = [self getSelectedIWAD];
+ [defaults setObject:IWADFilenames[selectedIWAD]
+ forKey:@"selected_iwad"];
+}
+
+// Callback method invoked when the configuration button in the main
+// window is clicked.
+
+- (void) openConfigWindow: (id)sender
+{
+ if (![self->configWindow isVisible])
+ {
+ [self->configWindow makeKeyAndOrderFront: sender];
+ }
+}
+
+// Callback method invoked when the close button is clicked.
+
+- (void) closeConfigWindow: (id)sender
+{
+ [self->configWindow orderOut: sender];
+ [self saveConfig];
+ [self setDropdownList];
+}
+
+- (void) awakeFromNib
+{
+ [self->configWindow center];
+
+ // Set configuration for all IWADs from configuration file.
+
+ [self setIWADConfig];
+
+ // Populate the dropdown IWAD list.
+
+ if ([self setDropdownList])
+ {
+ [self setDropdownSelection];
+ }
+}
+
+// Generate a value to set for the DOOMWADPATH environment variable
+// that contains each of the configured IWAD files.
+
+- (char *) doomWadPath
+{
+ IWADLocation *iwadList[NUM_IWAD_TYPES];
+ NSString *location;
+ unsigned int i;
+ unsigned int len;
+ BOOL first;
+ char *env;
+
+ [self getIWADList: iwadList];
+
+ // Calculate length of environment string.
+
+ len = 0;
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ location = [iwadList[i] getLocation];
+
+ if (location != nil && [location length] > 0)
+ {
+ len += [location length] + 1;
+ }
+ }
+
+ // Build string.
+
+ env = malloc(len);
+ strcpy(env, "");
+
+ first = YES;
+
+ for (i=0; i<NUM_IWAD_TYPES; ++i)
+ {
+ location = [iwadList[i] getLocation];
+
+ if (location != nil && [location length] > 0)
+ {
+ if (!first)
+ {
+ strcat(env, ":");
+ }
+
+ strcat(env, [location UTF8String]);
+ first = NO;
+ }
+ }
+
+ return env;
+}
+
+// Set the DOOMWADPATH environment variable to contain the path to each
+// of the configured IWAD files.
+
+- (void) setEnvironment
+{
+ char *doomwadpath;
+ char *env;
+
+ // Get the value for the path.
+
+ doomwadpath = [self doomWadPath];
+
+ env = malloc(strlen(doomwadpath) + 15);
+
+ sprintf(env, "DOOMWADPATH=%s", doomwadpath);
+
+ free(doomwadpath);
+
+ // Load into environment:
+
+ putenv(env);
+
+ //free(env);
+}
+
+@end
+
diff --git a/pkg/osx/IWADLocation.h b/pkg/osx/IWADLocation.h
new file mode 100644
index 00000000..4ddfebc2
--- /dev/null
+++ b/pkg/osx/IWADLocation.h
@@ -0,0 +1,44 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_IWADLOCATION_H
+#define LAUNCHER_IWADLOCATION_H
+
+#include <AppKit/AppKit.h>
+
+#include "IWADController.h"
+
+@interface IWADLocation : NSObject
+{
+ IWADController *iwadController;
+
+ id locationConfigBox;
+}
+
+- (void) setButtonClicked: (id)sender;
+- (NSString *) getLocation;
+- (void) setLocation: (NSString *) value;
+
+@end
+
+#endif /* #ifndef LAUNCHER_IWADLOCATION_H */
+
diff --git a/pkg/osx/IWADLocation.m b/pkg/osx/IWADLocation.m
new file mode 100644
index 00000000..3f2ac188
--- /dev/null
+++ b/pkg/osx/IWADLocation.m
@@ -0,0 +1,74 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <AppKit/AppKit.h>
+#include "IWADLocation.h"
+
+static id WAD_TYPES[] =
+{
+ @"wad", @"WAD"
+};
+
+@implementation IWADLocation
+
+- (void) setButtonClicked: (id)sender
+{
+ NSArray *wadTypes = [NSArray arrayWithObjects: WAD_TYPES count: 2];
+ NSOpenPanel *openPanel;
+ NSArray *filenames;
+ int result;
+
+ [wadTypes retain];
+
+ // Open a file selector for the new file.
+
+ openPanel = [NSOpenPanel openPanel];
+ [openPanel setTitle: @"Add IWAD file"];
+ [openPanel setCanChooseFiles: YES];
+ [openPanel setCanChooseDirectories: NO];
+
+ result = [openPanel runModalForTypes: wadTypes];
+
+ // If the "OK" button was clicked, add the new IWAD file to the list.
+
+ if (result == NSOKButton)
+ {
+ filenames = [openPanel filenames];
+ [self setLocation: [filenames lastObject]];
+
+ [self->iwadController saveConfig];
+ [self->iwadController setDropdownList];
+ }
+}
+
+- (NSString *) getLocation
+{
+ return [self->locationConfigBox stringValue];
+}
+
+- (void) setLocation: (NSString *) filename
+{
+ [self->locationConfigBox setStringValue: filename];
+}
+
+@end
+
diff --git a/pkg/osx/Info-gnustep.plist.in b/pkg/osx/Info-gnustep.plist.in
new file mode 100644
index 00000000..da6675ba
--- /dev/null
+++ b/pkg/osx/Info-gnustep.plist.in
@@ -0,0 +1,36 @@
+{
+ ApplicationName = "@PACKAGE_NAME@";
+ ApplicationDescription = "@PACKAGE_SHORTDESC@";
+ ApplicationIcon = app.png;
+ ApplicationRelease = @PACKAGE_VERSION@;
+ ApplicationURL = "@PACKAGE_URL@";
+ Authors = (
+ "@PACKAGE_MAINTAINER@ <@PACKAGE_BUGREPORT@>"
+ );
+ Copyright = "@PACKAGE_COPYRIGHT@";
+ CopyrightDescription = "@PACKAGE_LICENSE@";
+ FullVersionID = @PACKAGE_VERSION@;
+ GSMainMarkupFile = "";
+ NSExecutable = "launcher";
+ NSIcon = app.png;
+ NSMainNibFile = launcher.nib;
+ NSPrincipalClass = NSApplication;
+ NSRole = Application;
+ NSTypes = (
+ {
+ NSHumanReadableName = "Doom WAD file";
+ NSUnixExtensions = ( wad );
+ NSRole = Viewer;
+ NSMimeTypes = (
+ "application/x-doom"
+ );
+ NSIcon = "wadfile.png";
+ },
+ {
+ NSHumanReadableName = "Dehacked patch";
+ NSUnixExtensions = ( deh );
+ NSRole = Viewer;
+ NSIcon = "wadfile.png";
+ }
+ );
+}
diff --git a/pkg/osx/Info.plist.in b/pkg/osx/Info.plist.in
new file mode 100644
index 00000000..8b8436f7
--- /dev/null
+++ b/pkg/osx/Info.plist.in
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleDisplayName</key>
+ <string>@PACKAGE_NAME@</string>
+ <key>CFBundleExecutable</key>
+ <string>launcher</string>
+ <key>CFBundleGetInfoString</key>
+ <string>@PACKAGE_STRING@</string>
+ <key>CFBundleIconFile</key>
+ <string>app.icns</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>@PACKAGE_NAME@</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@PACKAGE_VERSION@</string>
+ <key>CFBundleVersion</key>
+ <string>@PACKAGE_VERSION@</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSMainNibFile</key>
+ <string>launcher</string>
+
+ <!-- file associations: -->
+
+ <key>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeName</key>
+ <string>Doom WAD file</string>
+ <key>CFBundleTypeIconFile</key>
+ <string>wadfile.icns</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>wad</string>
+ </array>
+ </dict>
+ <dict>
+ <key>CFBundleTypeName</key>
+ <string>Dehacked patch</string>
+ <key>CFBundleTypeIconFile</key>
+ <string>wadfile.icns</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>deh</string>
+ </array>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/pkg/osx/LauncherManager.h b/pkg/osx/LauncherManager.h
new file mode 100644
index 00000000..e454ab4f
--- /dev/null
+++ b/pkg/osx/LauncherManager.h
@@ -0,0 +1,52 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef LAUNCHER_LAUNCHERMANAGER_H
+#define LAUNCHER_LAUNCHERMANAGER_H
+
+#include <AppKit/AppKit.h>
+#include <AppKit/NSNibLoading.h>
+#include "IWADController.h"
+
+@interface LauncherManager : NSObject
+{
+ IWADController *iwadController;
+
+ id launcherWindow;
+ id launchButton;
+
+ id commandLineArguments;
+ id packageLabel;
+}
+
+- (void) launch: (id)sender;
+- (void) runSetup: (id)sender;
+- (void) awakeFromNib;
+- (void) clearCommandLine;
+- (void) addFileToCommandLine: (NSString *) fileName
+ forArgument: (NSString *) args;
+- (void) openTerminal: (id) sender;
+
+@end
+
+#endif /* #ifndef LAUNCHER_LAUNCHERMANAGER_H */
+
diff --git a/pkg/osx/LauncherManager.m b/pkg/osx/LauncherManager.m
new file mode 100644
index 00000000..ae91ef4d
--- /dev/null
+++ b/pkg/osx/LauncherManager.m
@@ -0,0 +1,338 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <AppKit/AppKit.h>
+#include "Execute.h"
+#include "LauncherManager.h"
+#include "config.h"
+
+@implementation LauncherManager
+
+// Save configuration. Invoked when we launch the game or quit.
+
+- (void) saveConfig
+{
+ NSUserDefaults *defaults;
+
+ // Save IWAD configuration and selected IWAD.
+
+ [self->iwadController saveConfig];
+
+ // Save command line arguments.
+
+ defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setObject:[self->commandLineArguments stringValue]
+ forKey:@"command_line_args"];
+}
+
+// Load configuration, invoked on startup.
+
+- (void) setConfig
+{
+ NSUserDefaults *defaults;
+ NSString *args;
+
+ defaults = [NSUserDefaults standardUserDefaults];
+
+ args = [defaults stringForKey:@"command_line_args"];
+
+ if (args != nil)
+ {
+ [self->commandLineArguments setStringValue:args];
+ }
+}
+
+// Get the next command line argument from the command line.
+// The position counter used to iterate over arguments is in 'pos'.
+// The index of the argument that was found is saved in arg_pos.
+
+static NSString *GetNextArgument(NSString *commandLine, int *pos, int *arg_pos)
+{
+ NSRange arg_range;
+
+ // Skip past any whitespace
+
+ while (*pos < [commandLine length]
+ && isspace([commandLine characterAtIndex: *pos]))
+ {
+ ++*pos;
+ }
+
+ if (*pos >= [commandLine length])
+ {
+ *arg_pos = *pos;
+ return nil;
+ }
+
+ // We are at the start of the argument. This may be a quoted
+ // string argument, or a "normal" one.
+
+ if ([commandLine characterAtIndex: *pos] == '\"')
+ {
+ // Quoted string, skip past first quote
+
+ ++*pos;
+
+ // Save start position:
+
+ *arg_pos = *pos;
+
+ while (*pos < [commandLine length]
+ && [commandLine characterAtIndex: *pos] != '\"')
+ {
+ ++*pos;
+ }
+
+ // Unexpected end of string?
+
+ if (*pos >= [commandLine length])
+ {
+ return nil;
+ }
+
+ arg_range = NSMakeRange(*arg_pos, *pos - *arg_pos);
+
+ // Skip past last quote
+
+ ++*pos;
+ }
+ else
+ {
+ // Normal argument
+
+ // Save position:
+
+ *arg_pos = *pos;
+
+ // Read until end:
+
+ while (*pos < [commandLine length]
+ && !isspace([commandLine characterAtIndex: *pos]))
+ {
+ ++*pos;
+ }
+
+ arg_range = NSMakeRange(*arg_pos, *pos - *arg_pos);
+ }
+
+ return [commandLine substringWithRange: arg_range];
+}
+
+// Given the specified command line argument, find the index
+// to insert the new file within the command line. Returns -1 if the
+// argument is not already within the arguments string.
+
+static int GetFileInsertIndex(NSString *commandLine, NSString *needle)
+{
+ NSString *arg;
+ int arg_pos;
+ int pos;
+
+ pos = 0;
+
+ // Find the command line parameter we are searching
+ // for (-merge, -deh, etc)
+
+ for (;;)
+ {
+ arg = GetNextArgument(commandLine, &pos, &arg_pos);
+
+ // Searched to end of string and never found?
+
+ if (arg == nil)
+ {
+ return -1;
+ }
+
+ if (![arg caseInsensitiveCompare: needle])
+ {
+ break;
+ }
+ }
+
+ // Now skip over existing files. For example, if we
+ // have -file foo.wad bar.wad, the new file should be appended
+ // to the end of the list.
+
+ for (;;)
+ {
+ arg = GetNextArgument(commandLine, &pos, &arg_pos);
+
+ // If we search to the end of the string now, it is fine;
+ // the new string should be added to the end of the command
+ // line. Otherwise, if we find an argument that begins
+ // with '-', it is a new command line parameter and the end
+ // of the list.
+
+ if (arg == nil || [arg characterAtIndex: 0] == '-')
+ {
+ break;
+ }
+ }
+
+ // arg_pos should now contain the offset to insert the new filename.
+
+ return arg_pos;
+}
+
+// Given the specified string, append a filename, quoted if necessary.
+
+static NSString *AppendQuotedFilename(NSString *str, NSString *fileName)
+{
+ int i;
+
+ // Search the filename for spaces, and quote if necessary.
+
+ for (i=0; i<[fileName length]; ++i)
+ {
+ if (isspace([fileName characterAtIndex: i]))
+ {
+ str = [str stringByAppendingString: @" \""];
+ str = [str stringByAppendingString: fileName];
+ str = [str stringByAppendingString: @"\" "];
+
+ return str;
+ }
+ }
+
+ str = [str stringByAppendingString: @" "];
+ str = [str stringByAppendingString: fileName];
+
+ return str;
+}
+
+// Clear out the existing command line options.
+// Invoked before the first file is added.
+
+- (void) clearCommandLine
+{
+ [self->commandLineArguments setStringValue: @""];
+}
+
+// Add a file to the command line to load with the game.
+
+- (void) addFileToCommandLine: (NSString *) fileName
+ forArgument: (NSString *) arg
+{
+ NSString *commandLine;
+ int insert_pos;
+
+ // Get the current command line
+
+ commandLine = [self->commandLineArguments stringValue];
+
+ // Find the location to insert the new filename:
+
+ insert_pos = GetFileInsertIndex(commandLine, arg);
+
+ // If position < 0, we should add the new argument and filename
+ // to the end. Otherwise, append the new filename to the existing
+ // list of files.
+
+ if (insert_pos < 0)
+ {
+ commandLine = [commandLine stringByAppendingString: @" "];
+ commandLine = [commandLine stringByAppendingString: arg];
+ commandLine = AppendQuotedFilename(commandLine, fileName);
+ }
+ else
+ {
+ NSString *start;
+ NSString *end;
+
+ // Divide existing command line in half:
+
+ start = [commandLine substringToIndex: insert_pos];
+ end = [commandLine substringFromIndex: insert_pos];
+
+ // Construct new command line:
+
+ commandLine = AppendQuotedFilename(start, fileName);
+ commandLine = [commandLine stringByAppendingString: @" "];
+ commandLine = [commandLine stringByAppendingString: end];
+ }
+
+ [self->commandLineArguments setStringValue: commandLine];
+}
+
+- (void) launch: (id)sender
+{
+ NSString *iwad;
+ NSString *args;
+
+ [self saveConfig];
+
+ iwad = [self->iwadController getIWADLocation];
+ args = [self->commandLineArguments stringValue];
+
+ if (iwad == nil)
+ {
+ NSRunAlertPanel(@"No IWAD selected",
+ @"You have not selected an IWAD (game) file.\n\n"
+ "You must configure and select a valid IWAD file "
+ "in order to launch the game.",
+ @"OK", nil, nil);
+ return;
+ }
+
+ ExecuteProgram(PACKAGE_TARNAME, [iwad UTF8String],
+ [args UTF8String]);
+ [NSApp terminate:sender];
+}
+
+// Invoked when the "Setup Tool" button is clicked, to run the setup tool:
+
+- (void) runSetup: (id)sender
+{
+ [self saveConfig];
+
+ [self->iwadController setEnvironment];
+ ExecuteProgram("chocolate-setup", NULL, NULL);
+}
+
+// Invoked when the "Terminal" option is selected from the menu, to open
+// a terminal window.
+
+- (void) openTerminal: (id) sender
+{
+ char *doomwadpath;
+
+ [self saveConfig];
+
+ doomwadpath = [self->iwadController doomWadPath];
+
+ OpenTerminalWindow(doomwadpath);
+
+ free(doomwadpath);
+}
+
+- (void) awakeFromNib
+{
+ [self->packageLabel setStringValue: @PACKAGE_STRING];
+ [self->launcherWindow setTitle: @PACKAGE_NAME " Launcher"];
+ [self->launcherWindow center];
+ [self->launcherWindow setDefaultButtonCell: [self->launchButton cell]];
+ [self setConfig];
+}
+
+@end
+
diff --git a/pkg/osx/PkgInfo b/pkg/osx/PkgInfo
new file mode 100644
index 00000000..6f749b0f
--- /dev/null
+++ b/pkg/osx/PkgInfo
@@ -0,0 +1 @@
+APPL????
diff --git a/pkg/osx/Resources/128x128.png b/pkg/osx/Resources/128x128.png
new file mode 100644
index 00000000..0ef1fe9c
--- /dev/null
+++ b/pkg/osx/Resources/128x128.png
Binary files differ
diff --git a/pkg/osx/Resources/app.icns b/pkg/osx/Resources/app.icns
new file mode 100644
index 00000000..9b535a25
--- /dev/null
+++ b/pkg/osx/Resources/app.icns
Binary files differ
diff --git a/pkg/osx/Resources/app.png b/pkg/osx/Resources/app.png
new file mode 100644
index 00000000..5b932e8c
--- /dev/null
+++ b/pkg/osx/Resources/app.png
Binary files differ
diff --git a/pkg/osx/Resources/launcher.nib/classes.nib b/pkg/osx/Resources/launcher.nib/classes.nib
new file mode 100644
index 00000000..7efc837a
--- /dev/null
+++ b/pkg/osx/Resources/launcher.nib/classes.nib
@@ -0,0 +1,47 @@
+{
+ IBClasses = (
+ {
+ CLASS = AppController;
+ LANGUAGE = ObjC;
+ OUTLETS = {launcherManager = id; };
+ SUPERCLASS = NSObject;
+ },
+ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
+ {
+ ACTIONS = {closeConfigWindow = id; openConfigWindow = id; };
+ CLASS = IWADController;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ chex = id;
+ configWindow = id;
+ doom1 = id;
+ doom2 = id;
+ iwadSelector = id;
+ plutonia = id;
+ tnt = id;
+ };
+ SUPERCLASS = NSObject;
+ },
+ {
+ ACTIONS = {setButtonClicked = id; };
+ CLASS = IWADLocation;
+ LANGUAGE = ObjC;
+ OUTLETS = {locationConfigBox = id; };
+ SUPERCLASS = NSObject;
+ },
+ {
+ ACTIONS = {launch = id; openTerminal = id; runSetup = id; };
+ CLASS = LauncherManager;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ commandLineArguments = id;
+ iwadController = id;
+ launchButton = id;
+ launcherWindow = id;
+ packageLabel = id;
+ };
+ SUPERCLASS = NSObject;
+ }
+ );
+ IBVersion = 1;
+} \ No newline at end of file
diff --git a/pkg/osx/Resources/launcher.nib/info.nib b/pkg/osx/Resources/launcher.nib/info.nib
new file mode 100644
index 00000000..512ee6dd
--- /dev/null
+++ b/pkg/osx/Resources/launcher.nib/info.nib
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>325 73 612 260 0 0 1440 878 </string>
+ <key>IBEditorPositions</key>
+ <dict>
+ <key>29</key>
+ <string>221 322 205 44 0 0 1440 878 </string>
+ </dict>
+ <key>IBFramework Version</key>
+ <string>446.1</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>29</integer>
+ <integer>21</integer>
+ <integer>227</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>8S2167</string>
+</dict>
+</plist>
diff --git a/pkg/osx/Resources/launcher.nib/keyedobjects.nib b/pkg/osx/Resources/launcher.nib/keyedobjects.nib
new file mode 100644
index 00000000..cc763056
--- /dev/null
+++ b/pkg/osx/Resources/launcher.nib/keyedobjects.nib
Binary files differ
diff --git a/pkg/osx/Resources/wadfile.icns b/pkg/osx/Resources/wadfile.icns
new file mode 100644
index 00000000..13502a55
--- /dev/null
+++ b/pkg/osx/Resources/wadfile.icns
Binary files differ
diff --git a/pkg/osx/Resources/wadfile.png b/pkg/osx/Resources/wadfile.png
new file mode 100644
index 00000000..394a3e33
--- /dev/null
+++ b/pkg/osx/Resources/wadfile.png
Binary files differ
diff --git a/pkg/osx/cp-with-libs b/pkg/osx/cp-with-libs
new file mode 100755
index 00000000..04fb5bc6
--- /dev/null
+++ b/pkg/osx/cp-with-libs
@@ -0,0 +1,100 @@
+#!/bin/bash
+#
+# Copy a program to the specified destination, along
+# with libraries it depends upon.
+
+src_bin=$1
+dest_dir=$2
+
+# Returns true if the specified file is a dylib.
+
+is_dylib() {
+ case "$1" in
+ *.dylib)
+ true
+ ;;
+ *)
+ false
+ ;;
+ esac
+}
+
+# Returns true if the specified file is in a system location
+# (/System or /usr):
+
+is_sys_lib() {
+ case "$1" in
+ /System/*)
+ true
+ ;;
+ /usr/*)
+ true
+ ;;
+ *)
+ false
+ ;;
+ esac
+}
+
+# Install the specified file to the location in dest_dir, along with
+# any libraries it depends upon (recursively):
+
+install_with_deps() {
+ local src_file
+ local bin_name
+ local dest_file
+ local lib_name
+
+ src_file=$1
+ bin_name=$(basename "$src_file")
+ dest_file="$dest_dir/$bin_name"
+
+ # Already copied into the package? Don't copy again.
+ # Prevents endless recursion.
+
+ if [ -e "$dest_file" ]; then
+ return
+ fi
+
+ echo "Installing $bin_name..."
+
+ # Copy file into package.
+
+ cp "$src_file" "$dest_file"
+
+ # Copy libraries that this file depends on:
+
+ otool -L "$src_file" | tail -n +2 | sed 's/^.//; s/ (.*//' | while read; do
+
+ # Don't copy system libraries
+
+ if is_sys_lib "$REPLY"; then
+ continue
+ fi
+
+ #echo " - $bin_name depends on $REPLY"
+
+ # Copy this library into the package, and:
+ # recursively install any libraries that _this_ library depends on:
+
+ install_with_deps "$REPLY"
+
+ # Change destination binary to depend on the
+ # copy inside the package:
+
+ lib_name=$(basename "$REPLY")
+ install_name_tool -change "$REPLY" "@executable_path/$lib_name" \
+ "$dest_file"
+ done
+
+ # If this is a library that we have installed, change its id:
+
+ if is_dylib "$dest_file"; then
+ install_name_tool -id "@executable_path/$bin_name" "$dest_file"
+ fi
+}
+
+# Install the file, and recursively install any libraries:
+
+install_with_deps "$src_bin"
+
diff --git a/pkg/osx/main.m b/pkg/osx/main.m
new file mode 100644
index 00000000..e3c70dc1
--- /dev/null
+++ b/pkg/osx/main.m
@@ -0,0 +1,32 @@
+/* ... */
+//-----------------------------------------------------------------------------
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+#include <AppKit/AppKit.h>
+#include "Execute.h"
+
+int main(int argc, const char *argv[])
+{
+ SetProgramLocation(argv[0]);
+
+ return NSApplicationMain (argc, argv);
+}
+
diff --git a/pkg/win32/GNUmakefile b/pkg/win32/GNUmakefile
new file mode 100644
index 00000000..147e2890
--- /dev/null
+++ b/pkg/win32/GNUmakefile
@@ -0,0 +1,34 @@
+
+include ../config.make
+
+TOPLEVEL=../..
+
+EXE_FILES=$(TOPLEVEL)/src/$(PROGRAM_PREFIX)doom.exe \
+ $(TOPLEVEL)/src/$(PROGRAM_PREFIX)heretic.exe \
+ $(TOPLEVEL)/src/$(PROGRAM_PREFIX)hexen.exe \
+ $(TOPLEVEL)/src/$(PROGRAM_PREFIX)server.exe \
+ $(TOPLEVEL)/src/$(PROGRAM_PREFIX)setup.exe
+
+DLL_FILES=$(TOPLEVEL)/src/SDL.dll \
+ $(TOPLEVEL)/src/SDL_mixer.dll \
+ $(TOPLEVEL)/src/SDL_net.dll
+
+ZIP=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-win32.zip
+
+$(ZIP) : staging
+ zip -j -r $@ staging/
+
+staging: $(EXE_FILES) $(DLL_FILES) $(patsubst %,../../%,$(DOC_FILES))
+ rm -rf staging
+ mkdir staging
+ cp $(EXE_FILES) $(DLL_FILES) staging/
+ $(STRIP) staging/*.exe
+ for f in $(DOC_FILES); do \
+ cp $(TOPLEVEL)/$$f staging/$$f.txt; \
+ unix2dos staging/$$f.txt; \
+ done
+
+clean:
+ rm -f $(ZIP)
+ rm -rf staging
+
diff --git a/pkg/win32/GNUmakefile.am b/pkg/win32/GNUmakefile.am
deleted file mode 100644
index 47d5ac63..00000000
--- a/pkg/win32/GNUmakefile.am
+++ /dev/null
@@ -1,37 +0,0 @@
-
-TOPLEVEL=../..
-
-EXE_FILES=$(TOPLEVEL)/src/@PROGRAM_PREFIX@doom.exe \
- $(TOPLEVEL)/src/@PROGRAM_PREFIX@heretic.exe \
- $(TOPLEVEL)/src/@PROGRAM_PREFIX@hexen.exe \
- $(TOPLEVEL)/src/@PROGRAM_PREFIX@server.exe \
- $(TOPLEVEL)/src/@PROGRAM_PREFIX@setup.exe
-
-DLL_FILES=$(TOPLEVEL)/src/SDL.dll \
- $(TOPLEVEL)/src/SDL_mixer.dll \
- $(TOPLEVEL)/src/SDL_net.dll
-
-DOC_FILES=README \
- COPYING \
- ChangeLog \
- NEWS \
- BUGS \
- CMDLINE \
- HH-TODO \
- TODO
-
-noinst_DATA=@PACKAGE_TARNAME@-@PACKAGE_VERSION@-win32.zip
-
-@PACKAGE_TARNAME@-@PACKAGE_VERSION@-win32.zip : staging
- zip -j -r $@ staging/
-
-staging: $(EXE_FILES) $(DLL_FILES) $(patsubst %,../../%,$(DOC_FILES))
- rm -rf staging
- mkdir staging
- cp $(EXE_FILES) $(DLL_FILES) staging/
- $(STRIP) staging/*.exe
- for f in $(DOC_FILES); do \
- cp $(TOPLEVEL)/$$f staging/$$f.txt; \
- unix2dos staging/$$f.txt; \
- done
-
diff --git a/pkg/wince/GNUmakefile.am b/pkg/wince/GNUmakefile
index a203e63c..82b1f1e3 100644
--- a/pkg/wince/GNUmakefile.am
+++ b/pkg/wince/GNUmakefile
@@ -1,7 +1,14 @@
+include ../config.make
+
+all: $(DOOM_CAB) $(HERETIC_CAB) $(HEXEN_CAB)
+
+clean:
+ rm -f $(DOOM_CAB) $(HERETIC_CAB) $(HEXEN_CAB)
+
# Doom:
-DOOM_CAB=chocolate-doom-@PACKAGE_VERSION@.cab
+DOOM_CAB=$(PROGRAM_PREFIX)doom-$(PACKAGE_VERSION).cab
DOOM_CFG=doom-cab.cfg
DOOM_DEPS=$(shell ./wince-cabgen -d $(DOOM_CFG))
@@ -10,7 +17,7 @@ $(DOOM_CAB) : $(DOOM_CFG) $(DOOM_DEPS)
# Heretic:
-HERETIC_CAB=chocolate-heretic-@PACKAGE_VERSION@.cab
+HERETIC_CAB=$(PROGRAM_PREFIX)heretic-$(PACKAGE_VERSION).cab
HERETIC_CFG=heretic-cab.cfg
HERETIC_DEPS=$(shell ./wince-cabgen -d $(HERETIC_CFG))
@@ -19,12 +26,10 @@ $(HERETIC_CAB) : $(HERETIC_CFG) $(HERETIC_DEPS)
# Hexen:
-HEXEN_CAB=chocolate-hexen-@PACKAGE_VERSION@.cab
+HEXEN_CAB=$(PROGRAM_PREFIX)hexen-$(PACKAGE_VERSION).cab
HEXEN_CFG=hexen-cab.cfg
HEXEN_DEPS=$(shell ./wince-cabgen -d $(HEXEN_CFG))
$(HEXEN_CAB) : $(HEXEN_CFG) $(HEXEN_DEPS)
./wince-cabgen $< $@
-noinst_DATA = $(DOOM_CAB) $(HERETIC_CAB) $(HEXEN_CAB)
-
diff --git a/rpm.spec.in b/rpm.spec.in
new file mode 100644
index 00000000..1b7e90c7
--- /dev/null
+++ b/rpm.spec.in
@@ -0,0 +1,59 @@
+
+Name: @PACKAGE@
+Summary: @PACKAGE_SHORTDESC@
+Version: @VERSION@
+Release: 1
+Source: http://mesh.dl.sourceforge.net/project/chocolate-doom/@PACKAGE@/@VERSION@/@PACKAGE@-@VERSION@.tar.gz
+URL: @PACKAGE_URL@
+Group: Amusements/Games
+BuildRoot: /var/tmp/@PACKAGE@-buildroot
+License: @PACKAGE_LICENSE@
+Packager: @PACKAGE_MAINTAINER@ <@PACKAGE_BUGREPORT@>
+Prefix: %{_prefix}
+Autoreq: 0
+Requires: libSDL-1.2.so.0, libSDL_mixer-1.2.so.0, libSDL_net-1.2.so.0
+
+%description
+%(sed -n "/==/ q; p " < README)
+
+See @PACKAGE_URL@ for more information.
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+
+%setup -q
+
+%build
+./configure \
+ --prefix=/usr \
+ --exec-prefix=/usr \
+ --bindir=/usr/bin \
+ --sbindir=/usr/sbin \
+ --sysconfdir=/etc \
+ --datadir=/usr/share \
+ --includedir=/usr/include \
+ --libdir=/usr/lib \
+ --libexecdir=/usr/lib \
+ --localstatedir=/var/lib \
+ --sharedstatedir=/usr/com \
+ --mandir=/usr/share/man \
+ --infodir=/usr/share/info
+make
+
+%install
+%makeinstall
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%doc %{_mandir}/man5/*
+%doc %{_mandir}/man6/*
+%doc NEWS
+%doc AUTHORS
+%doc README
+%doc COPYING
+%doc CMDLINE
+%doc BUGS
+/usr/games/*
+
diff --git a/src/.gitignore b/src/.gitignore
index d7e732ad..973a0073 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -5,3 +5,5 @@ Makefile.in
chocolate-doom
chocolate-server
*.exe
+tags
+TAGS
diff --git a/src/Makefile.am b/src/Makefile.am
index fc7e8852..9e550e15 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -190,7 +190,7 @@ EXTRA_DIST = \
if HAVE_PYTHON
-icon.c : $(top_builddir)/data/doom.ico
+icon.c : $(top_builddir)/data/doom8.ico
$(top_builddir)/data/convert-icon $^ $@
endif
diff --git a/src/d_iwad.c b/src/d_iwad.c
index ba9f9ae1..ab1dd823 100644
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -330,44 +330,85 @@ static void CheckDOSDefaults(void)
#endif
+// Returns true if the specified path is a path to a file
+// of the specified name.
+
+static boolean DirIsFile(char *path, char *filename)
+{
+ size_t path_len;
+ size_t filename_len;
+
+ path_len = strlen(path);
+ filename_len = strlen(filename);
+
+ return path_len >= filename_len + 1
+ && path[path_len - filename_len - 1] == DIR_SEPARATOR
+ && !strcasecmp(&path[path_len - filename_len], filename);
+}
+
+// Check if the specified directory contains the specified IWAD
+// file, returning the full path to the IWAD if found, or NULL
+// if not found.
+
+static char *CheckDirectoryHasIWAD(char *dir, char *iwadname)
+{
+ char *filename;
+
+ // As a special case, the "directory" may refer directly to an
+ // IWAD file if the path comes from DOOMWADDIR or DOOMWADPATH.
+
+ if (DirIsFile(dir, iwadname) && M_FileExists(dir))
+ {
+ return strdup(dir);
+ }
+
+ // Construct the full path to the IWAD if it is located in
+ // this directory, and check if it exists.
+
+ filename = malloc(strlen(dir) + strlen(iwadname) + 3);
+
+ if (!strcmp(dir, "."))
+ {
+ strcpy(filename, iwadname);
+ }
+ else
+ {
+ sprintf(filename, "%s%c%s", dir, DIR_SEPARATOR, iwadname);
+ }
+
+ if (M_FileExists(filename))
+ {
+ return filename;
+ }
+
+ free(filename);
+
+ return NULL;
+}
+
// Search a directory to try to find an IWAD
// Returns the location of the IWAD if found, otherwise NULL.
static char *SearchDirectoryForIWAD(char *dir, int mask, GameMission_t *mission)
{
+ char *filename;
size_t i;
for (i=0; i<arrlen(iwads); ++i)
{
- char *filename;
- char *iwadname;
-
if (((1 << iwads[i].mission) & mask) == 0)
{
continue;
}
- iwadname = DEH_String(iwads[i].name);
-
- filename = malloc(strlen(dir) + strlen(iwadname) + 3);
-
- if (!strcmp(dir, "."))
- {
- strcpy(filename, iwadname);
- }
- else
- {
- sprintf(filename, "%s%c%s", dir, DIR_SEPARATOR, iwadname);
- }
+ filename = CheckDirectoryHasIWAD(dir, DEH_String(iwads[i].name));
- if (M_FileExists(filename))
+ if (filename != NULL)
{
*mission = iwads[i].mission;
return filename;
}
-
- free(filename);
}
return NULL;
@@ -528,7 +569,6 @@ char *D_FindWADByName(char *name)
{
char *buf;
int i;
- boolean exists;
// Absolute path?
@@ -543,14 +583,21 @@ char *D_FindWADByName(char *name)
for (i=0; i<num_iwad_dirs; ++i)
{
+ // As a special case, if this is in DOOMWADDIR or DOOMWADPATH,
+ // the "directory" may actually refer directly to an IWAD
+ // file.
+
+ if (DirIsFile(iwad_dirs[i], name) && M_FileExists(iwad_dirs[i]))
+ {
+ return strdup(iwad_dirs[i]);
+ }
+
// Construct a string for the full path
buf = malloc(strlen(iwad_dirs[i]) + strlen(name) + 5);
sprintf(buf, "%s%c%s", iwad_dirs[i], DIR_SEPARATOR, name);
- exists = M_FileExists(buf);
-
- if (exists)
+ if (M_FileExists(buf))
{
return buf;
}
diff --git a/src/doom/.gitignore b/src/doom/.gitignore
index d7e732ad..973a0073 100644
--- a/src/doom/.gitignore
+++ b/src/doom/.gitignore
@@ -5,3 +5,5 @@ Makefile.in
chocolate-doom
chocolate-server
*.exe
+tags
+TAGS
diff --git a/src/doom/g_game.c b/src/doom/g_game.c
index 35bf4d74..8d0e4503 100644
--- a/src/doom/g_game.c
+++ b/src/doom/g_game.c
@@ -588,10 +588,20 @@ void G_BuildTiccmd (ticcmd_t* cmd)
if (lowres_turn)
{
- // round angleturn to the nearest 256 boundary
+ static signed short carry = 0;
+ signed short desired_angleturn;
+
+ desired_angleturn = cmd->angleturn + carry;
+
+ // round angleturn to the nearest 256 unit boundary
// for recording demos with single byte values for turn
- cmd->angleturn = (cmd->angleturn + 128) & 0xff00;
+ cmd->angleturn = (desired_angleturn + 128) & 0xff00;
+
+ // Carry forward the error from the reduced resolution to the
+ // next tic, so that successive small movements can accumulate.
+
+ carry = desired_angleturn - cmd->angleturn;
}
}
diff --git a/src/doom/hu_stuff.c b/src/doom/hu_stuff.c
index a106978e..ca74ce92 100644
--- a/src/doom/hu_stuff.c
+++ b/src/doom/hu_stuff.c
@@ -52,9 +52,9 @@
// Locally used constants, shortcuts.
//
#define HU_TITLE (mapnames[(gameepisode-1)*9+gamemap-1])
-#define HU_TITLE2 (mapnames2[gamemap-1])
-#define HU_TITLEP (mapnamesp[gamemap-1])
-#define HU_TITLET (mapnamest[gamemap-1])
+#define HU_TITLE2 (mapnames_commercial[gamemap-1])
+#define HU_TITLEP (mapnames_commercial[gamemap-1 + 32])
+#define HU_TITLET (mapnames_commercial[gamemap-1 + 64])
#define HU_TITLE_CHEX (mapnames[gamemap - 1])
#define HU_TITLEHEIGHT 1
#define HU_TITLEX 0
@@ -171,8 +171,16 @@ char* mapnames[] = // DOOM shareware/registered/retail (Ultimate) names.
"NEWLEVEL"
};
-char* mapnames2[] = // DOOM 2 map names.
+// List of names for levels in commercial IWADs
+// (doom2.wad, plutonia.wad, tnt.wad). These are stored in a
+// single large array; WADs like pl2.wad have a MAP33, and rely on
+// the layout in the Vanilla executable, where it is possible to
+// overflow the end of one array into the next.
+
+char *mapnames_commercial[] =
{
+ // DOOM 2 map names.
+
HUSTR_1,
HUSTR_2,
HUSTR_3,
@@ -206,12 +214,10 @@ char* mapnames2[] = // DOOM 2 map names.
HUSTR_29,
HUSTR_30,
HUSTR_31,
- HUSTR_32
-};
+ HUSTR_32,
+ // Plutonia WAD map names.
-char* mapnamesp[] = // Plutonia WAD map names.
-{
PHUSTR_1,
PHUSTR_2,
PHUSTR_3,
@@ -245,12 +251,10 @@ char* mapnamesp[] = // Plutonia WAD map names.
PHUSTR_29,
PHUSTR_30,
PHUSTR_31,
- PHUSTR_32
-};
-
+ PHUSTR_32,
+
+ // TNT WAD map names.
-char *mapnamest[] = // TNT WAD map names.
-{
THUSTR_1,
THUSTR_2,
THUSTR_3,
diff --git a/src/doom/p_map.c b/src/doom/p_map.c
index 3f88aabc..925e4398 100644
--- a/src/doom/p_map.c
+++ b/src/doom/p_map.c
@@ -885,7 +885,17 @@ PTR_AimTraverse (intercept_t* in)
dist = FixedMul (attackrange, in->frac);
- if (li->frontsector->floorheight != li->backsector->floorheight)
+ // Return false if there is no back sector. This should never
+ // be the case if the line is two-sided; however, some WADs
+ // (eg. ottawau.wad) use this as an "impassible glass" trick
+ // and rely on Vanilla Doom's (unintentional) support for this.
+
+ if (li->backsector == NULL)
+ {
+ return false;
+ }
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
{
slope = FixedDiv (openbottom - shootz , dist);
if (slope > bottomslope)
@@ -973,7 +983,14 @@ boolean PTR_ShootTraverse (intercept_t* in)
dist = FixedMul (attackrange, in->frac);
- if (li->frontsector->floorheight != li->backsector->floorheight)
+ // Check if backsector is NULL. See comment in PTR_AimTraverse.
+
+ if (li->backsector == NULL)
+ {
+ goto hitline;
+ }
+
+ if (li->frontsector->floorheight != li->backsector->floorheight)
{
slope = FixedDiv (openbottom - shootz , dist);
if (slope > aimslope)
diff --git a/src/doom/p_setup.c b/src/doom/p_setup.c
index 5cf7a628..2a3a8f85 100644
--- a/src/doom/p_setup.c
+++ b/src/doom/p_setup.c
@@ -167,6 +167,7 @@ void P_LoadSegs (int lump)
line_t* ldef;
int linedef;
int side;
+ int sidenum;
numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0);
@@ -179,7 +180,7 @@ void P_LoadSegs (int lump)
{
li->v1 = &vertexes[SHORT(ml->v1)];
li->v2 = &vertexes[SHORT(ml->v2)];
-
+
li->angle = (SHORT(ml->angle))<<16;
li->offset = (SHORT(ml->offset))<<16;
linedef = SHORT(ml->linedef);
@@ -188,10 +189,28 @@ void P_LoadSegs (int lump)
side = SHORT(ml->side);
li->sidedef = &sides[ldef->sidenum[side]];
li->frontsector = sides[ldef->sidenum[side]].sector;
- if (ldef-> flags & ML_TWOSIDED)
- li->backsector = sides[ldef->sidenum[side^1]].sector;
- else
+
+ if (ldef-> flags & ML_TWOSIDED)
+ {
+ sidenum = ldef->sidenum[side ^ 1];
+
+ // If the sidenum is out of range, this may be a "glass hack"
+ // impassible window. Point at side #0 (this may not be
+ // the correct Vanilla behavior; however, it seems to work for
+ // OTTAWAU.WAD, which is the one place I've seen this trick
+ // used).
+
+ if (sidenum < 0 || sidenum >= numsides)
+ {
+ sidenum = 0;
+ }
+
+ li->backsector = sides[sidenum].sector;
+ }
+ else
+ {
li->backsector = 0;
+ }
}
W_ReleaseLumpNum(lump);
diff --git a/src/doom/p_sight.c b/src/doom/p_sight.c
index e192567b..79c1bb1d 100644
--- a/src/doom/p_sight.c
+++ b/src/doom/p_sight.c
@@ -173,7 +173,7 @@ boolean P_CrossSubsector (int num)
continue;
line->validcount = validcount;
-
+
v1 = line->v1;
v2 = line->v2;
s1 = P_DivlineSide (v1->x,v1->y, &strace);
@@ -194,6 +194,14 @@ boolean P_CrossSubsector (int num)
if (s1 == s2)
continue;
+ // Backsector may be NULL if this is an "impassible
+ // glass" hack line.
+
+ if (line->backsector == NULL)
+ {
+ return false;
+ }
+
// stop because it is not two sided anyway
// might do this after updating validcount?
if ( !(line->flags & ML_TWOSIDED) )
diff --git a/src/doom/st_stuff.c b/src/doom/st_stuff.c
index e6ef0828..160244ce 100644
--- a/src/doom/st_stuff.c
+++ b/src/doom/st_stuff.c
@@ -260,9 +260,6 @@
// Height, in lines.
#define ST_OUTHEIGHT 1
-#define ST_MAPWIDTH \
- (strlen(mapnames[(gameepisode-1)*9+(gamemap-1)]))
-
#define ST_MAPTITLEX \
(SCREENWIDTH - ST_MAPWIDTH * ST_CHATFONTWIDTH)
@@ -418,10 +415,6 @@ cheatseq_t cheat_clev = CHEAT("idclev", 2);
cheatseq_t cheat_mypos = CHEAT("idmypos", 0);
-//
-extern char* mapnames[];
-
-
//
// STATUS BAR CODE
//
@@ -985,6 +978,17 @@ void ST_doPaletteStuff(void)
else
palette = 0;
+ // In Chex Quest, the player never sees red. Instead, the
+ // radiation suit palette is used to tint the screen green,
+ // as though the player is being covered in goo by an
+ // attacking flemoid.
+
+ if (gameversion == exe_chex
+ && palette >= STARTREDPALS && palette < STARTREDPALS + NUMREDPALS)
+ {
+ palette = RADIATIONPAL;
+ }
+
if (palette != st_palette)
{
st_palette = palette;
diff --git a/src/i_video.c b/src/i_video.c
index 64a2e8eb..a370fc08 100644
--- a/src/i_video.c
+++ b/src/i_video.c
@@ -503,6 +503,7 @@ void I_ShutdownGraphics(void)
{
if (initialized)
{
+ SDL_SetCursor(cursors[1]);
SDL_ShowCursor(1);
SDL_WM_GrabInput(SDL_GRAB_OFF);
diff --git a/src/mus2mid.c b/src/mus2mid.c
index 8ba1a5ff..88d24c97 100644
--- a/src/mus2mid.c
+++ b/src/mus2mid.c
@@ -1,4 +1,4 @@
-// Emacs style mode select -*- C++ -*-
+// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright(C) 1993-1996 Id Software, Inc.
@@ -31,594 +31,663 @@
#include "memio.h"
#include "mus2mid.h"
+#define NUM_CHANNELS 16
+
+#define MIDI_PERCUSSION_CHAN 9
+#define MUS_PERCUSSION_CHAN 15
+
// MUS event codes
-typedef enum
+typedef enum
{
- mus_releasekey = 0x00,
- mus_presskey = 0x10,
- mus_pitchwheel = 0x20,
- mus_systemevent = 0x30,
- mus_changecontroller = 0x40,
- mus_scoreend = 0x60
+ mus_releasekey = 0x00,
+ mus_presskey = 0x10,
+ mus_pitchwheel = 0x20,
+ mus_systemevent = 0x30,
+ mus_changecontroller = 0x40,
+ mus_scoreend = 0x60
} musevent;
// MIDI event codes
-typedef enum
+typedef enum
{
- midi_releasekey = 0x80,
- midi_presskey = 0x90,
- midi_aftertouchkey = 0xA0,
- midi_changecontroller = 0xB0,
- midi_changepatch = 0xC0,
- midi_aftertouchchannel = 0xD0,
- midi_pitchwheel = 0xE0
+ midi_releasekey = 0x80,
+ midi_presskey = 0x90,
+ midi_aftertouchkey = 0xA0,
+ midi_changecontroller = 0xB0,
+ midi_changepatch = 0xC0,
+ midi_aftertouchchannel = 0xD0,
+ midi_pitchwheel = 0xE0
} midievent;
-
// Structure to hold MUS file header
-typedef struct
+typedef struct
{
- byte id[4];
- unsigned short scorelength;
- unsigned short scorestart;
- unsigned short primarychannels;
- unsigned short secondarychannels;
- unsigned short instrumentcount;
+ byte id[4];
+ unsigned short scorelength;
+ unsigned short scorestart;
+ unsigned short primarychannels;
+ unsigned short secondarychannels;
+ unsigned short instrumentcount;
} PACKEDATTR musheader;
// Standard MIDI type 0 header + track header
-static byte midiheader[] =
+static const byte midiheader[] =
{
- 'M', 'T', 'h', 'd', // Main header
- 0x00, 0x00, 0x00, 0x06, // Header size
- 0x00, 0x00, // MIDI type (0)
- 0x00, 0x01, // Number of tracks
- 0x00, 0x46, // Resolution
- 'M', 'T', 'r', 'k', // Start of track
- 0x00, 0x00, 0x00, 0x00 // Placeholder for track length
+ 'M', 'T', 'h', 'd', // Main header
+ 0x00, 0x00, 0x00, 0x06, // Header size
+ 0x00, 0x00, // MIDI type (0)
+ 0x00, 0x01, // Number of tracks
+ 0x00, 0x46, // Resolution
+ 'M', 'T', 'r', 'k', // Start of track
+ 0x00, 0x00, 0x00, 0x00 // Placeholder for track length
};
// Cached channel velocities
-static byte channelvelocities[] =
-{
- 127, 127, 127, 127, 127, 127, 127, 127,
- 127, 127, 127, 127, 127, 127, 127, 127
+static byte channelvelocities[] =
+{
+ 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127
};
// Timestamps between sequences of MUS events
-static unsigned int queuedtime = 0;
+static unsigned int queuedtime = 0;
// Counter for the length of the track
static unsigned int tracksize;
-static byte mus2midi_translation[] =
-{
- 0x00, 0x20, 0x01, 0x07, 0x0A, 0x0B, 0x5B, 0x5D,
- 0x40, 0x43, 0x78, 0x7B, 0x7E, 0x7F, 0x79
+static const byte controller_map[] =
+{
+ 0x00, 0x20, 0x01, 0x07, 0x0A, 0x0B, 0x5B, 0x5D,
+ 0x40, 0x43, 0x78, 0x7B, 0x7E, 0x7F, 0x79
};
+static int channel_map[NUM_CHANNELS];
+
// Write timestamp to a MIDI file.
-static boolean midi_writetime(unsigned int time, MEMFILE *midioutput)
+static boolean WriteTime(unsigned int time, MEMFILE *midioutput)
{
- unsigned int buffer = time & 0x7F;
- byte writeval;
-
- while ((time >>= 7) != 0)
- {
- buffer <<= 8;
- buffer |= ((time & 0x7F) | 0x80);
- }
-
- for (;;)
- {
- writeval = (byte)(buffer & 0xFF);
-
- if (mem_fwrite(&writeval, 1, 1, midioutput) != 1)
- {
- return true;
- }
-
- ++tracksize;
-
- if ((buffer & 0x80) != 0)
- {
- buffer >>= 8;
- }
- else
- {
- queuedtime = 0;
- return false;
- }
- }
+ unsigned int buffer = time & 0x7F;
+ byte writeval;
+
+ while ((time >>= 7) != 0)
+ {
+ buffer <<= 8;
+ buffer |= ((time & 0x7F) | 0x80);
+ }
+
+ for (;;)
+ {
+ writeval = (byte)(buffer & 0xFF);
+
+ if (mem_fwrite(&writeval, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
+
+ ++tracksize;
+
+ if ((buffer & 0x80) != 0)
+ {
+ buffer >>= 8;
+ }
+ else
+ {
+ queuedtime = 0;
+ return false;
+ }
+ }
}
// Write the end of track marker
-static boolean midi_writeendtrack(MEMFILE *midioutput)
+static boolean WriteEndTrack(MEMFILE *midioutput)
{
- byte endtrack[] = {0xFF, 0x2F, 0x00};
+ byte endtrack[] = {0xFF, 0x2F, 0x00};
- if (midi_writetime(queuedtime, midioutput))
- {
- return true;
- }
+ if (WriteTime(queuedtime, midioutput))
+ {
+ return true;
+ }
- if (mem_fwrite(endtrack, 1, 3, midioutput) != 3)
- {
- return true;
- }
+ if (mem_fwrite(endtrack, 1, 3, midioutput) != 3)
+ {
+ return true;
+ }
- tracksize += 3;
- return false;
+ tracksize += 3;
+ return false;
}
// Write a key press event
-static boolean midi_writepresskey(byte channel, byte key,
- byte velocity, MEMFILE *midioutput)
+static boolean WritePressKey(byte channel, byte key,
+ byte velocity, MEMFILE *midioutput)
{
- byte working = midi_presskey | channel;
-
- if (midi_writetime(queuedtime, midioutput))
- {
- return true;
- }
-
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
-
- working = key & 0x7F;
-
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
-
- working = velocity & 0x7F;
-
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
-
- tracksize += 3;
-
- return false;
+ byte working = midi_presskey | channel;
+
+ if (WriteTime(queuedtime, midioutput))
+ {
+ return true;
+ }
+
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
+
+ working = key & 0x7F;
+
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
+
+ working = velocity & 0x7F;
+
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
+
+ tracksize += 3;
+
+ return false;
}
// Write a key release event
-static boolean midi_writereleasekey(byte channel, byte key,
- MEMFILE *midioutput)
+static boolean WriteReleaseKey(byte channel, byte key,
+ MEMFILE *midioutput)
{
- byte working = midi_releasekey | channel;
+ byte working = midi_releasekey | channel;
- if (midi_writetime(queuedtime, midioutput))
- {
- return true;
- }
+ if (WriteTime(queuedtime, midioutput))
+ {
+ return true;
+ }
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- working = key & 0x7F;
+ working = key & 0x7F;
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- working = 0;
+ working = 0;
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- tracksize += 3;
+ tracksize += 3;
- return false;
+ return false;
}
// Write a pitch wheel/bend event
-static boolean midi_writepitchwheel(byte channel, short wheel,
- MEMFILE *midioutput)
+static boolean WritePitchWheel(byte channel, short wheel,
+ MEMFILE *midioutput)
{
- byte working = midi_pitchwheel | channel;
+ byte working = midi_pitchwheel | channel;
- if (midi_writetime(queuedtime, midioutput))
- {
- return true;
- }
+ if (WriteTime(queuedtime, midioutput))
+ {
+ return true;
+ }
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- working = wheel & 0x7F;
+ working = wheel & 0x7F;
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- working = (wheel >> 7) & 0x7F;
+ working = (wheel >> 7) & 0x7F;
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- tracksize += 3;
- return false;
+ tracksize += 3;
+ return false;
}
// Write a patch change event
-static boolean midi_writechangepatch(byte channel, byte patch,
- MEMFILE *midioutput)
+static boolean WriteChangePatch(byte channel, byte patch,
+ MEMFILE *midioutput)
{
- byte working = midi_changepatch | channel;
-
- if (midi_writetime(queuedtime, midioutput))
- {
- return true;
- }
+ byte working = midi_changepatch | channel;
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ if (WriteTime(queuedtime, midioutput))
+ {
+ return true;
+ }
- working = patch & 0x7F;
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ working = patch & 0x7F;
- tracksize += 2;
-
- return false;
-}
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
+ tracksize += 2;
+ return false;
+}
// Write a valued controller change event
-static boolean midi_writechangecontroller_valued(byte channel,
- byte control,
- byte value,
- MEMFILE *midioutput)
+
+static boolean WriteChangeController_Valued(byte channel,
+ byte control,
+ byte value,
+ MEMFILE *midioutput)
{
- byte working = midi_changecontroller | channel;
+ byte working = midi_changecontroller | channel;
+
+ if (WriteTime(queuedtime, midioutput))
+ {
+ return true;
+ }
- if (midi_writetime(queuedtime, midioutput))
- {
- return true;
- }
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ working = control & 0x7F;
- working = control & 0x7F;
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
- // Quirk in vanilla DOOM? MUS controller values should be
- // 7-bit, not 8-bit.
+ // Quirk in vanilla DOOM? MUS controller values should be
+ // 7-bit, not 8-bit.
- working = value;// & 0x7F;
+ working = value;// & 0x7F;
- // Fix on said quirk to stop MIDI players from complaining that
- // the value is out of range:
+ // Fix on said quirk to stop MIDI players from complaining that
+ // the value is out of range:
- if (working & 0x80)
- {
- working = 0x7F;
- }
+ if (working & 0x80)
+ {
+ working = 0x7F;
+ }
- if (mem_fwrite(&working, 1, 1, midioutput) != 1)
- {
- return true;
- }
+ if (mem_fwrite(&working, 1, 1, midioutput) != 1)
+ {
+ return true;
+ }
- tracksize += 3;
+ tracksize += 3;
- return false;
+ return false;
}
// Write a valueless controller change event
-static boolean midi_writechangecontroller_valueless(byte channel,
- byte control,
- MEMFILE *midioutput)
+static boolean WriteChangeController_Valueless(byte channel,
+ byte control,
+ MEMFILE *midioutput)
{
- return midi_writechangecontroller_valued(channel, control, 0,
- midioutput);
+ return WriteChangeController_Valued(channel, control, 0,
+ midioutput);
}
-static boolean read_musheader(MEMFILE *file, musheader *header)
+// Allocate a free MIDI channel.
+
+static int AllocateMIDIChannel(void)
{
- boolean result;
-
- result = (mem_fread(&header->id, sizeof(byte), 4, file) == 4)
- && (mem_fread(&header->scorelength, sizeof(short), 1, file) == 1)
- && (mem_fread(&header->scorestart, sizeof(short), 1, file) == 1)
- && (mem_fread(&header->primarychannels, sizeof(short), 1, file) == 1)
- && (mem_fread(&header->secondarychannels, sizeof(short), 1, file) == 1)
- && (mem_fread(&header->instrumentcount, sizeof(short), 1, file) == 1);
-
- if (result)
- {
- header->scorelength = SHORT(header->scorelength);
- header->scorestart = SHORT(header->scorestart);
- header->primarychannels = SHORT(header->primarychannels);
- header->secondarychannels = SHORT(header->secondarychannels);
- header->instrumentcount = SHORT(header->instrumentcount);
- }
-
- return result;
+ int result;
+ int max;
+ int i;
+
+ // Find the current highest-allocated channel.
+
+ max = -1;
+
+ for (i=0; i<NUM_CHANNELS; ++i)
+ {
+ if (channel_map[i] > max)
+ {
+ max = channel_map[i];
+ }
+ }
+
+ // max is now equal to the highest-allocated MIDI channel. We can
+ // now allocate the next available channel. This also works if
+ // no channels are currently allocated (max=-1)
+
+ result = max + 1;
+
+ // Don't allocate the MIDI percussion channel!
+
+ if (result == MIDI_PERCUSSION_CHAN)
+ {
+ ++result;
+ }
+
+ return result;
}
+// Given a MUS channel number, get the MIDI channel number to use
+// in the outputted file.
-// Read a MUS file from a stream (musinput) and output a MIDI file to
+static int GetMIDIChannel(int mus_channel)
+{
+ // Find the MIDI channel to use for this MUS channel.
+ // MUS channel 15 is the percusssion channel.
+
+ if (mus_channel == MUS_PERCUSSION_CHAN)
+ {
+ return MIDI_PERCUSSION_CHAN;
+ }
+ else
+ {
+ // If a MIDI channel hasn't been allocated for this MUS channel
+ // yet, allocate the next free MIDI channel.
+
+ if (channel_map[mus_channel] == -1)
+ {
+ channel_map[mus_channel] = AllocateMIDIChannel();
+ }
+
+ return channel_map[mus_channel];
+ }
+}
+
+static boolean ReadMusHeader(MEMFILE *file, musheader *header)
+{
+ boolean result;
+
+ result = mem_fread(&header->id, sizeof(byte), 4, file) == 4
+ && mem_fread(&header->scorelength, sizeof(short), 1, file) == 1
+ && mem_fread(&header->scorestart, sizeof(short), 1, file) == 1
+ && mem_fread(&header->primarychannels, sizeof(short), 1, file) == 1
+ && mem_fread(&header->secondarychannels, sizeof(short), 1, file) == 1
+ && mem_fread(&header->instrumentcount, sizeof(short), 1, file) == 1;
+
+ if (result)
+ {
+ header->scorelength = SHORT(header->scorelength);
+ header->scorestart = SHORT(header->scorestart);
+ header->primarychannels = SHORT(header->primarychannels);
+ header->secondarychannels = SHORT(header->secondarychannels);
+ header->instrumentcount = SHORT(header->instrumentcount);
+ }
+
+ return result;
+}
+
+
+// Read a MUS file from a stream (musinput) and output a MIDI file to
// a stream (midioutput).
//
// Returns 0 on success or 1 on failure.
-boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput)
+boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput)
{
- // Header for the MUS file
- musheader musfileheader;
+ // Header for the MUS file
+ musheader musfileheader;
+
+ // Descriptor for the current MUS event
+ byte eventdescriptor;
+ int channel; // Channel number
+ musevent event;
+
+
+ // Bunch of vars read from MUS lump
+ byte key;
+ byte controllernumber;
+ byte controllervalue;
- // Descriptor for the current MUS event
- byte eventdescriptor;
- int channel; // Channel number
- musevent event;
-
+ // Buffer used for MIDI track size record
+ byte tracksizebuffer[4];
- // Bunch of vars read from MUS lump
- byte key;
- byte controllernumber;
- byte controllervalue;
+ // Flag for when the score end marker is hit.
+ int hitscoreend = 0;
- // Buffer used for MIDI track size record
- byte tracksizebuffer[4];
+ // Temp working byte
+ byte working;
+ // Used in building up time delays
+ unsigned int timedelay;
- // Flag for when the score end marker is hit.
- int hitscoreend = 0;
+ // Initialise channel map to mark all channels as unused.
- // Temp working byte
- byte working;
- // Used in building up time delays
- unsigned int timedelay;
+ for (channel=0; channel<NUM_CHANNELS; ++channel)
+ {
+ channel_map[channel] = -1;
+ }
- // Grab the header
+ // Grab the header
- if (!read_musheader(musinput, &musfileheader))
- {
- return true;
- }
+ if (!ReadMusHeader(musinput, &musfileheader))
+ {
+ return true;
+ }
#ifdef CHECK_MUS_HEADER
- // Check MUS header
- if (musfileheader.id[0] != 'M'
- || musfileheader.id[1] != 'U'
- || musfileheader.id[2] != 'S'
- || musfileheader.id[3] != 0x1A)
- {
- return true;
- }
+ // Check MUS header
+ if (musfileheader.id[0] != 'M'
+ || musfileheader.id[1] != 'U'
+ || musfileheader.id[2] != 'S'
+ || musfileheader.id[3] != 0x1A)
+ {
+ return true;
+ }
#endif
- // Seek to where the data is held
- if (mem_fseek(musinput, (long)musfileheader.scorestart,
- MEM_SEEK_SET) != 0)
- {
- return true;
- }
-
- // So, we can assume the MUS file is faintly legit. Let's start
- // writing MIDI data...
-
- mem_fwrite(midiheader, 1, sizeof(midiheader), midioutput);
- tracksize = 0;
-
- // Now, process the MUS file:
- while (!hitscoreend)
- {
- // Handle a block of events:
-
- while (!hitscoreend)
- {
- // Fetch channel number and event code:
-
- if (mem_fread(&eventdescriptor, 1, 1, musinput) != 1)
- {
- return true;
- }
-
- channel = eventdescriptor & 0x0F;
- event = eventdescriptor & 0x70;
-
- // Swap channels 15 and 9.
- // MIDI channel 9 = percussion.
- // MUS channel 15 = percussion.
-
- if (channel == 15)
- {
- channel = 9;
- }
- else if (channel == 9)
- {
- channel = 15;
- }
-
- switch (event)
- {
- case mus_releasekey:
- if (mem_fread(&key, 1, 1, musinput) != 1)
- {
- return true;
- }
-
- if (midi_writereleasekey(channel, key, midioutput))
- {
- return true;
- }
-
- break;
-
- case mus_presskey:
- if (mem_fread(&key, 1, 1, musinput) != 1)
- {
- return true;
- }
-
- if (key & 0x80)
- {
- if (mem_fread(&channelvelocities[channel], 1, 1, musinput) != 1)
- {
- return true;
- }
-
- channelvelocities[channel] &= 0x7F;
- }
-
- if (midi_writepresskey(channel, key, channelvelocities[channel], midioutput))
- {
- return true;
- }
-
- break;
-
- case mus_pitchwheel:
- if (mem_fread(&key, 1, 1, musinput) != 1)
- {
- break;
- }
- if (midi_writepitchwheel(channel, (short)(key * 64), midioutput))
- {
- return true;
- }
-
- break;
-
- case mus_systemevent:
- if (mem_fread(&controllernumber, 1, 1, musinput) != 1)
- {
- return true;
- }
- if (controllernumber < 10 || controllernumber > 14)
- {
- return true;
- }
-
- if (midi_writechangecontroller_valueless(channel, mus2midi_translation[controllernumber], midioutput))
- {
- return true;
- }
-
- break;
-
- case mus_changecontroller:
- if (mem_fread(&controllernumber, 1, 1, musinput) != 1)
- {
- return true;
- }
-
- if (mem_fread(&controllervalue, 1, 1, musinput) != 1)
- {
- return true;
- }
-
- if (controllernumber == 0)
- {
- if (midi_writechangepatch(channel, controllervalue, midioutput))
- {
- return true;
- }
- }
- else
- {
- if (controllernumber < 1 || controllernumber > 9)
- {
- return true;
- }
-
- if (midi_writechangecontroller_valued(channel, mus2midi_translation[controllernumber], controllervalue, midioutput))
- {
- return true;
- }
- }
-
- break;
-
- case mus_scoreend:
- hitscoreend = 1;
- break;
-
- default:
- return true;
- break;
- }
-
- if (eventdescriptor & 0x80)
- {
- break;
- }
- }
- // Now we need to read the time code:
- if (!hitscoreend)
- {
- timedelay = 0;
- for (;;)
- {
- if (mem_fread(&working, 1, 1, musinput) != 1)
- {
- return true;
- }
-
- timedelay = timedelay * 128 + (working & 0x7F);
- if ((working & 0x80) == 0)
- {
- break;
- }
- }
- queuedtime += timedelay;
- }
- }
-
- // End of track
- if (midi_writeendtrack(midioutput))
- {
- return true;
- }
-
- // Write the track size into the stream
- if (mem_fseek(midioutput, 18, MEM_SEEK_SET))
- {
- return true;
- }
-
- tracksizebuffer[0] = (tracksize >> 24) & 0xff;
- tracksizebuffer[1] = (tracksize >> 16) & 0xff;
- tracksizebuffer[2] = (tracksize >> 8) & 0xff;
- tracksizebuffer[3] = tracksize & 0xff;
-
- if (mem_fwrite(tracksizebuffer, 1, 4, midioutput) != 4)
- {
- return true;
- }
-
- return false;
+ // Seek to where the data is held
+ if (mem_fseek(musinput, (long)musfileheader.scorestart,
+ MEM_SEEK_SET) != 0)
+ {
+ return true;
+ }
+
+ // So, we can assume the MUS file is faintly legit. Let's start
+ // writing MIDI data...
+
+ mem_fwrite(midiheader, 1, sizeof(midiheader), midioutput);
+ tracksize = 0;
+
+ // Now, process the MUS file:
+ while (!hitscoreend)
+ {
+ // Handle a block of events:
+
+ while (!hitscoreend)
+ {
+ // Fetch channel number and event code:
+
+ if (mem_fread(&eventdescriptor, 1, 1, musinput) != 1)
+ {
+ return true;
+ }
+
+ channel = GetMIDIChannel(eventdescriptor & 0x0F);
+ event = eventdescriptor & 0x70;
+
+ switch (event)
+ {
+ case mus_releasekey:
+ if (mem_fread(&key, 1, 1, musinput) != 1)
+ {
+ return true;
+ }
+
+ if (WriteReleaseKey(channel, key, midioutput))
+ {
+ return true;
+ }
+
+ break;
+
+ case mus_presskey:
+ if (mem_fread(&key, 1, 1, musinput) != 1)
+ {
+ return true;
+ }
+
+ if (key & 0x80)
+ {
+ if (mem_fread(&channelvelocities[channel], 1, 1, musinput) != 1)
+ {
+ return true;
+ }
+
+ channelvelocities[channel] &= 0x7F;
+ }
+
+ if (WritePressKey(channel, key,
+ channelvelocities[channel], midioutput))
+ {
+ return true;
+ }
+
+ break;
+
+ case mus_pitchwheel:
+ if (mem_fread(&key, 1, 1, musinput) != 1)
+ {
+ break;
+ }
+ if (WritePitchWheel(channel, (short)(key * 64), midioutput))
+ {
+ return true;
+ }
+
+ break;
+
+ case mus_systemevent:
+ if (mem_fread(&controllernumber, 1, 1, musinput) != 1)
+ {
+ return true;
+ }
+ if (controllernumber < 10 || controllernumber > 14)
+ {
+ return true;
+ }
+
+ if (WriteChangeController_Valueless(channel,
+ controller_map[controllernumber],
+ midioutput))
+ {
+ return true;
+ }
+
+ break;
+
+ case mus_changecontroller:
+ if (mem_fread(&controllernumber, 1, 1, musinput) != 1)
+ {
+ return true;
+ }
+
+ if (mem_fread(&controllervalue, 1, 1, musinput) != 1)
+ {
+ return true;
+ }
+
+ if (controllernumber == 0)
+ {
+ if (WriteChangePatch(channel, controllervalue,
+ midioutput))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (controllernumber < 1 || controllernumber > 9)
+ {
+ return true;
+ }
+
+ if (WriteChangeController_Valued(channel,
+ controller_map[controllernumber],
+ controllervalue,
+ midioutput))
+ {
+ return true;
+ }
+ }
+
+ break;
+
+ case mus_scoreend:
+ hitscoreend = 1;
+ break;
+
+ default:
+ return true;
+ break;
+ }
+
+ if (eventdescriptor & 0x80)
+ {
+ break;
+ }
+ }
+ // Now we need to read the time code:
+ if (!hitscoreend)
+ {
+ timedelay = 0;
+ for (;;)
+ {
+ if (mem_fread(&working, 1, 1, musinput) != 1)
+ {
+ return true;
+ }
+
+ timedelay = timedelay * 128 + (working & 0x7F);
+ if ((working & 0x80) == 0)
+ {
+ break;
+ }
+ }
+ queuedtime += timedelay;
+ }
+ }
+
+ // End of track
+ if (WriteEndTrack(midioutput))
+ {
+ return true;
+ }
+
+ // Write the track size into the stream
+ if (mem_fseek(midioutput, 18, MEM_SEEK_SET))
+ {
+ return true;
+ }
+
+ tracksizebuffer[0] = (tracksize >> 24) & 0xff;
+ tracksizebuffer[1] = (tracksize >> 16) & 0xff;
+ tracksizebuffer[2] = (tracksize >> 8) & 0xff;
+ tracksizebuffer[3] = tracksize & 0xff;
+
+ if (mem_fwrite(tracksizebuffer, 1, 4, midioutput) != 4)
+ {
+ return true;
+ }
+
+ return false;
}
diff --git a/src/resource.rc.in b/src/resource.rc.in
index 7eb5d00f..f8b64331 100644
--- a/src/resource.rc.in
+++ b/src/resource.rc.in
@@ -13,7 +13,7 @@ FILETYPE 1
VALUE "FileDescription", "@PACKAGE_STRING@"
VALUE "InternalName", "@PACKAGE_TARNAME@"
VALUE "CompanyName", "@PACKAGE_BUGREPORT@"
- VALUE "LegalCopyright", "GNU General Public License"
+ VALUE "LegalCopyright", "@PACKAGE_COPYRIGHT@. Licensed under @PACKAGE_LICENSE@"
VALUE "ProductName", "@PACKAGE_NAME@"
VALUE "ProductVersion", "@PACKAGE_VERSION@"
}
diff --git a/src/setup/.gitignore b/src/setup/.gitignore
index d7e732ad..37c8e4c1 100644
--- a/src/setup/.gitignore
+++ b/src/setup/.gitignore
@@ -1,7 +1,8 @@
-Makefile
Makefile.in
+Makefile
.deps
+chocolate-setup
*.rc
-chocolate-doom
-chocolate-server
*.exe
+tags
+TAGS
diff --git a/src/setup/Makefile.am b/src/setup/Makefile.am
index 07d7c936..25ab38e3 100644
--- a/src/setup/Makefile.am
+++ b/src/setup/Makefile.am
@@ -27,3 +27,10 @@ libsetup_a_SOURCES = $(SOURCE_FILES)
EXTRA_DIST= \
setup_icon.c
+if HAVE_PYTHON
+
+setup_icon.c : $(top_builddir)/data/setup8.ico
+ $(top_builddir)/data/convert-icon $^ $@
+
+endif
+
diff --git a/src/setup/execute.c b/src/setup/execute.c
index be7214f5..4be44149 100644
--- a/src/setup/execute.c
+++ b/src/setup/execute.c
@@ -172,29 +172,38 @@ static void ConcatWCString(wchar_t *buf, const char *value)
static wchar_t *BuildCommandLine(const char *program, const char *arg)
{
+ wchar_t exe_path[MAX_PATH];
wchar_t *result;
- char *sep;
+ wchar_t *sep;
+
+ // Get the path to this .exe file.
+
+ GetModuleFileNameW(NULL, exe_path, MAX_PATH);
- result = calloc(strlen(myargv[0]) + strlen(program) + strlen(arg) + 6,
+ // Allocate buffer to contain result string.
+
+ result = calloc(wcslen(exe_path) + strlen(program) + strlen(arg) + 6,
sizeof(wchar_t));
wcscpy(result, L"\"");
- sep = strrchr(myargv[0], DIR_SEPARATOR);
+ // Copy the path part of the filename (including ending \)
+ // into the result buffer:
+
+ sep = wcsrchr(exe_path, DIR_SEPARATOR);
if (sep != NULL)
{
- ConcatWCString(result, myargv[0]);
-
- // Cut off the string after the last directory separator,
- // before appending the actual program.
-
- result[sep - myargv[0] + 2] = '\0';
-
+ wcsncpy(result + 1, exe_path, sep - exe_path + 1);
+ result[sep - exe_path + 2] = '\0';
}
+ // Concatenate the name of the program:
+
ConcatWCString(result, program);
+ // End of program name, start of argument:
+
wcscat(result, L"\" \"");
ConcatWCString(result, arg);
@@ -290,7 +299,7 @@ static int ExecuteCommand(const char *program, const char *arg)
execvp(argv[0], (char **) argv);
- exit(-1);
+ exit(0x80);
}
else
{
@@ -299,7 +308,7 @@ static int ExecuteCommand(const char *program, const char *arg)
waitpid(childpid, &result, 0);
- if (WIFEXITED(result))
+ if (WIFEXITED(result) && WEXITSTATUS(result) != 0x80)
{
return WEXITSTATUS(result);
}
diff --git a/textscreen/.gitignore b/textscreen/.gitignore
index 6f6e5b3b..3be8ec0c 100644
--- a/textscreen/.gitignore
+++ b/textscreen/.gitignore
@@ -2,3 +2,5 @@ Makefile
Makefile.in
.deps
*.a
+tags
+TAGS
diff --git a/textscreen/examples/.gitignore b/textscreen/examples/.gitignore
index b75bfc6b..cb0fd52c 100644
--- a/textscreen/examples/.gitignore
+++ b/textscreen/examples/.gitignore
@@ -4,3 +4,5 @@ Makefile
guitest
calculator
*.exe
+tags
+TAGS
diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c
index 71736720..a0cbe3d6 100644
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -289,10 +289,10 @@ void TXT_UpdateScreenArea(int x, int y, int w, int h)
int x_end;
int y_end;
- x_end = LimitToRange(x + w, 0, TXT_SCREEN_W - 1);
- y_end = LimitToRange(y + h, 0, TXT_SCREEN_H - 1);
- x = LimitToRange(x, 0, TXT_SCREEN_W - 1);
- y = LimitToRange(y, 0, TXT_SCREEN_H - 1);
+ x_end = LimitToRange(x + w, 0, TXT_SCREEN_W);
+ y_end = LimitToRange(y + h, 0, TXT_SCREEN_H);
+ x = LimitToRange(x, 0, TXT_SCREEN_W);
+ y = LimitToRange(y, 0, TXT_SCREEN_H);
for (y1=y; y1<y_end; ++y1)
{
diff --git a/wince/.gitignore b/wince/.gitignore
new file mode 100644
index 00000000..d4e88e5a
--- /dev/null
+++ b/wince/.gitignore
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+.deps
+tags
+TAGS
diff --git a/wince/Makefile.am b/wince/Makefile.am
index 476b9a67..c19471ca 100644
--- a/wince/Makefile.am
+++ b/wince/Makefile.am
@@ -4,6 +4,7 @@ noinst_LIBRARIES=libc_wince.a
if WINDOWS_CE
libc_wince_a_SOURCES = \
+ libc_wince.h \
env.c env.h \
errno.c errno.h \
fileops.c fileops.h