diff options
92 files changed, 3019 insertions, 1836 deletions
@@ -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 @@ -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/ > $@ @@ -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): @@ -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? @@ -8,5 +8,5 @@ automake -a -c autoconf automake -./configure $@ +./configure "$@" diff --git a/configure.in b/configure.in index f8482d53..de537f7c 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,28 +126,36 @@ 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 -src/strife/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 +src/strife/Makefile +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 Binary files differindex f55ff28f..025cb698 100644 --- a/data/doom.ico +++ b/data/doom.ico diff --git a/data/doom8.ico b/data/doom8.ico Binary files differnew file mode 100644 index 00000000..f55ff28f --- /dev/null +++ b/data/doom8.ico diff --git a/data/setup.ico b/data/setup.ico Binary files differindex 6d734a11..dae4e5ec 100644 --- a/data/setup.ico +++ b/data/setup.ico diff --git a/data/setup8.ico b/data/setup8.ico Binary files differnew file mode 100644 index 00000000..6d734a11 --- /dev/null +++ b/data/setup8.ico 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/src/strife/deh_main.h b/pkg/osx/AppController.h index f9cb44ca..88b59043 100644 --- a/src/strife/deh_main.h +++ b/pkg/osx/AppController.h @@ -1,7 +1,7 @@ -// Emacs style mode select -*- C++ -*- +/* ... */ //----------------------------------------------------------------------------- // -// Copyright(C) 2005 Simon Howard +// 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 @@ -19,36 +19,35 @@ // 02111-1307, USA. // //----------------------------------------------------------------------------- -// -// Dehacked entrypoint and common code -// -//----------------------------------------------------------------------------- -#ifndef DEH_MAIN_H -#define DEH_MAIN_H +#ifndef LAUNCHER_APPCONTROLLER_H +#define LAUNCHER_APPCONTROLLER_H + +#include <AppKit/AppKit.h> + +#include "LauncherManager.h" -#include "doomtype.h" -#include "doomfeatures.h" -#include "md5.h" -#include "deh_str.h" +@interface AppController : NSObject +{ + LauncherManager *launcherManager; + BOOL filesAdded; +} -// These are the limits that dehacked uses (from dheinit.h in the dehacked -// source). If these limits are exceeded, it does not generate an error, but -// a warning is displayed. ++ (void)initialize; -#define DEH_VANILLA_NUMSTATES 966 -#define DEH_VANILLA_NUMSFX 107 +- (id)init; +- (void)dealloc; -void DEH_Init(void); -int DEH_LoadFile(char *filename); +- (void)awakeFromNib; -boolean DEH_ParseAssignment(char *line, char **variable_name, char **value); +- (void)applicationDidFinishLaunching:(NSNotification *)aNotif; +- (BOOL)applicationShouldTerminate:(id)sender; +- (void)applicationWillTerminate:(NSNotification *)aNotif; +- (BOOL)application:(NSApplication *)application openFile:(NSString *)fileName; -void DEH_Checksum(md5_digest_t digest); +- (void)showPrefPanel:(id)sender; -extern boolean deh_allow_long_strings; -extern boolean deh_allow_long_cheats; -extern boolean deh_apply_cheats; +@end -#endif /* #ifndef DEH_MAIN_H */ +#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..a0f6151f --- /dev/null +++ b/pkg/osx/GNUmakefile @@ -0,0 +1,105 @@ + +# 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/$(PROGRAM_PREFIX)doom "$(APP_BIN_DIR)" + $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)doom" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)heretic "$(APP_BIN_DIR)" + $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)heretic" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)hexen "$(APP_BIN_DIR)" + $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)hexen" + ./cp-with-libs $(TOPLEVEL)/src/$(PROGRAM_PREFIX)setup "$(APP_BIN_DIR)" + $(STRIP) "$(APP_BIN_DIR)/$(PROGRAM_PREFIX)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/src/strife/deh_io.h b/pkg/osx/IWADLocation.h index 061a5a0e..4ddfebc2 100644 --- a/src/strife/deh_io.h +++ b/pkg/osx/IWADLocation.h @@ -1,7 +1,7 @@ -// Emacs style mode select -*- C++ -*- +/* ... */ //----------------------------------------------------------------------------- // -// Copyright(C) 2005 Simon Howard +// 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 @@ -19,22 +19,26 @@ // 02111-1307, USA. // //----------------------------------------------------------------------------- -// -// Dehacked I/O code (does all reads from dehacked files) -// -//----------------------------------------------------------------------------- -#ifndef DEH_IO_H -#define DEH_IO_H +#ifndef LAUNCHER_IWADLOCATION_H +#define LAUNCHER_IWADLOCATION_H + +#include <AppKit/AppKit.h> + +#include "IWADController.h" + +@interface IWADLocation : NSObject +{ + IWADController *iwadController; + + id locationConfigBox; +} -#include "deh_defs.h" +- (void) setButtonClicked: (id)sender; +- (NSString *) getLocation; +- (void) setLocation: (NSString *) value; -deh_context_t *DEH_OpenFile(char *filename); -void DEH_CloseFile(deh_context_t *context); -int DEH_GetChar(deh_context_t *context); -char *DEH_ReadLine(deh_context_t *context); -void DEH_Error(deh_context_t *context, char *msg, ...); -void DEH_Warning(deh_context_t *context, char *msg, ...); +@end -#endif /* #ifndef DEH_IO_H */ +#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 Binary files differnew file mode 100644 index 00000000..0ef1fe9c --- /dev/null +++ b/pkg/osx/Resources/128x128.png diff --git a/pkg/osx/Resources/app.icns b/pkg/osx/Resources/app.icns Binary files differnew file mode 100644 index 00000000..9b535a25 --- /dev/null +++ b/pkg/osx/Resources/app.icns diff --git a/pkg/osx/Resources/app.png b/pkg/osx/Resources/app.png Binary files differnew file mode 100644 index 00000000..5b932e8c --- /dev/null +++ b/pkg/osx/Resources/app.png 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 Binary files differnew file mode 100644 index 00000000..cc763056 --- /dev/null +++ b/pkg/osx/Resources/launcher.nib/keyedobjects.nib diff --git a/pkg/osx/Resources/wadfile.icns b/pkg/osx/Resources/wadfile.icns Binary files differnew file mode 100644 index 00000000..13502a55 --- /dev/null +++ b/pkg/osx/Resources/wadfile.icns diff --git a/pkg/osx/Resources/wadfile.png b/pkg/osx/Resources/wadfile.png Binary files differnew file mode 100644 index 00000000..394a3e33 --- /dev/null +++ b/pkg/osx/Resources/wadfile.png 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..3b8171aa 100644 --- a/pkg/wince/GNUmakefile.am +++ b/pkg/wince/GNUmakefile @@ -1,30 +1,35 @@ +include ../config.make + # 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)) -$(DOOM_CAB) : $(DOOM_CFG) $(DOOM_DEPS) - ./wince-cabgen $< $@ - # 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)) -$(HERETIC_CAB) : $(HERETIC_CFG) $(HERETIC_DEPS) - ./wince-cabgen $< $@ - # 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)) +all: $(DOOM_CAB) $(HERETIC_CAB) $(HEXEN_CAB) + +$(DOOM_CAB) : $(DOOM_CFG) $(DOOM_DEPS) + ./wince-cabgen $< $@ + +$(HERETIC_CAB) : $(HERETIC_CFG) $(HERETIC_DEPS) + ./wince-cabgen $< $@ + $(HEXEN_CAB) : $(HEXEN_CFG) $(HEXEN_DEPS) ./wince-cabgen $< $@ -noinst_DATA = $(DOOM_CAB) $(HERETIC_CAB) $(HEXEN_CAB) +clean: + rm -f $(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 82a7697f..51baa567 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,7 @@ d_event.c d_event.h \ d_iwad.c d_iwad.h \ d_mode.c d_mode.h \ d_ticcmd.h \ +deh_str.c deh_str.h \ i_cdmus.c i_cdmus.h \ i_endoom.c i_endoom.h \ i_joystick.c i_joystick.h \ @@ -80,8 +81,12 @@ z_zone.c z_zone.h # source files needed for FEATURE_DEHACKED -FEATURE_DEHACKED_SOURCE_FILES= \ -deh_str.c deh_str.h +FEATURE_DEHACKED_SOURCE_FILES = \ +deh_defs.h \ +deh_io.c deh_io.h \ +deh_main.c deh_main.h \ +deh_mapping.c deh_mapping.h \ +deh_text.c # source files needed for FEATURE_MULTIPLAYER @@ -112,12 +117,15 @@ i_sdlsound.c \ i_sdlmusic.c \ mus2mid.c mus2mid.h +# Some games support dehacked patches, some don't: + SOURCE_FILES = $(COMMON_SOURCE_FILES) \ $(GAME_SOURCE_FILES) \ - $(FEATURE_DEHACKED_SOURCE_FILES) \ $(FEATURE_WAD_MERGE_SOURCE_FILES) \ $(FEATURE_SOUND_SOURCE_FILES) +SOURCE_FILES_WITH_DEH = $(SOURCE_FILES) \ + $(FEATURE_DEHACKED_SOURCE_FILES) EXTRA_LIBS = \ $(top_builddir)/wince/libc_wince.a \ @@ -129,9 +137,9 @@ EXTRA_LIBS = \ @SDLNET_LIBS@ if HAVE_WINDRES -@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES) resource.rc +@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc else -@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES) +@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) endif @PROGRAM_PREFIX@doom_LDADD = doom/libdoom.a $(EXTRA_LIBS) @@ -153,9 +161,9 @@ endif @PROGRAM_PREFIX@hexen_LDADD = hexen/libhexen.a $(EXTRA_LIBS) if HAVE_WINDRES -@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES) resource.rc +@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc else -@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES) +@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) endif @PROGRAM_PREFIX@strife_LDADD = strife/libstrife.a $(EXTRA_LIBS) @@ -191,7 +199,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 fe60866b..0e3220a8 100644 --- a/src/d_iwad.c +++ b/src/d_iwad.c @@ -331,44 +331,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; @@ -529,7 +570,6 @@ char *D_FindWADByName(char *name) { char *buf; int i; - boolean exists; // Absolute path? @@ -544,14 +584,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/deh_defs.h b/src/deh_defs.h index e7b76182..e7b76182 100644 --- a/src/doom/deh_defs.h +++ b/src/deh_defs.h diff --git a/src/doom/deh_io.c b/src/deh_io.c index 3386a6fa..3386a6fa 100644 --- a/src/doom/deh_io.c +++ b/src/deh_io.c diff --git a/src/doom/deh_io.h b/src/deh_io.h index 061a5a0e..061a5a0e 100644 --- a/src/doom/deh_io.h +++ b/src/deh_io.h diff --git a/src/doom/deh_main.c b/src/deh_main.c index 63cae460..3f0a6f29 100644 --- a/src/doom/deh_main.c +++ b/src/deh_main.c @@ -36,30 +36,8 @@ #include "deh_defs.h" #include "deh_io.h" -static char *deh_signatures[] = -{ - "Patch File for DeHackEd v2.3", - "Patch File for DeHackEd v3.0", -}; - -// deh_ammo.c: -extern deh_section_t deh_section_ammo; -// deh_cheat.c: -extern deh_section_t deh_section_cheat; -// deh_frame.c: -extern deh_section_t deh_section_frame; -// deh_misc.c: -extern deh_section_t deh_section_misc; -// deh_ptr.c: -extern deh_section_t deh_section_pointer; -// deh_sound.c -extern deh_section_t deh_section_sound; -// deh_text.c: -extern deh_section_t deh_section_text; -// deh_thing.c: -extern deh_section_t deh_section_thing; -// deh_weapon.c: -extern deh_section_t deh_section_weapon; +extern deh_section_t *deh_section_types[]; +extern char *deh_signatures[]; // If true, we can do long string replacements. @@ -73,23 +51,6 @@ boolean deh_allow_long_cheats = false; boolean deh_apply_cheats = true; -// -// List of section types: -// - -static deh_section_t *section_types[] = -{ - &deh_section_ammo, - &deh_section_cheat, - &deh_section_frame, - &deh_section_misc, - &deh_section_pointer, - &deh_section_sound, - &deh_section_text, - &deh_section_thing, - &deh_section_weapon, -}; - void DEH_Checksum(md5_digest_t digest) { md5_context_t md5_context; @@ -97,11 +58,11 @@ void DEH_Checksum(md5_digest_t digest) MD5_Init(&md5_context); - for (i=0; i<arrlen(section_types); ++i) + for (i=0; deh_section_types[i] != NULL; ++i) { - if (section_types[i]->md5_hash != NULL) + if (deh_section_types[i]->md5_hash != NULL) { - section_types[i]->md5_hash(&md5_context); + deh_section_types[i]->md5_hash(&md5_context); } } @@ -114,11 +75,11 @@ static void InitializeSections(void) { unsigned int i; - for (i=0; i<arrlen(section_types); ++i) + for (i=0; deh_section_types[i] != NULL; ++i) { - if (section_types[i]->init != NULL) + if (deh_section_types[i]->init != NULL) { - section_types[i]->init(); + deh_section_types[i]->init(); } } } @@ -129,11 +90,11 @@ static deh_section_t *GetSectionByName(char *name) { unsigned int i; - for (i=0; i<arrlen(section_types); ++i) + for (i=0; deh_section_types[i] != NULL; ++i) { - if (!strcasecmp(section_types[i]->name, name)) + if (!strcasecmp(deh_section_types[i]->name, name)) { - return section_types[i]; + return deh_section_types[i]; } } @@ -229,7 +190,7 @@ static boolean CheckSignatures(deh_context_t *context) // Check all signatures to see if one matches - for (i=0; i<arrlen(deh_signatures); ++i) + for (i=0; deh_signatures[i] != NULL; ++i) { if (!strcmp(deh_signatures[i], line)) { diff --git a/src/doom/deh_main.h b/src/deh_main.h index f9cb44ca..f9cb44ca 100644 --- a/src/doom/deh_main.h +++ b/src/deh_main.h diff --git a/src/doom/deh_mapping.c b/src/deh_mapping.c index b215b128..b215b128 100644 --- a/src/doom/deh_mapping.c +++ b/src/deh_mapping.c diff --git a/src/doom/deh_mapping.h b/src/deh_mapping.h index 4862dec9..4862dec9 100644 --- a/src/doom/deh_mapping.h +++ b/src/deh_mapping.h diff --git a/src/doom/deh_text.c b/src/deh_text.c index 31e23db2..31e23db2 100644 --- a/src/doom/deh_text.c +++ b/src/deh_text.c 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/Makefile.am b/src/doom/Makefile.am index 7b7073b6..596e42eb 100644 --- a/src/doom/Makefile.am +++ b/src/doom/Makefile.am @@ -63,15 +63,11 @@ wi_stuff.c wi_stuff.h FEATURE_DEHACKED_SOURCE_FILES = \ deh_ammo.c \ deh_cheat.c \ -deh_defs.h \ +deh_doom.c \ deh_frame.c \ -deh_io.c deh_io.h \ -deh_main.c deh_main.h \ -deh_mapping.c deh_mapping.h \ deh_misc.c deh_misc.h \ deh_ptr.c \ deh_sound.c \ -deh_text.c \ deh_thing.c \ deh_weapon.c diff --git a/src/doom/deh_doom.c b/src/doom/deh_doom.c new file mode 100644 index 00000000..7549e09e --- /dev/null +++ b/src/doom/deh_doom.c @@ -0,0 +1,74 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Top-level dehacked definitions for Doom dehacked. +// +//----------------------------------------------------------------------------- + +#include <stdlib.h> +#include "deh_defs.h" +#include "deh_main.h" + +char *deh_signatures[] = +{ + "Patch File for DeHackEd v2.3", + "Patch File for DeHackEd v3.0", + NULL +}; + +// deh_ammo.c: +extern deh_section_t deh_section_ammo; +// deh_cheat.c: +extern deh_section_t deh_section_cheat; +// deh_frame.c: +extern deh_section_t deh_section_frame; +// deh_misc.c: +extern deh_section_t deh_section_misc; +// deh_ptr.c: +extern deh_section_t deh_section_pointer; +// deh_sound.c +extern deh_section_t deh_section_sound; +// deh_text.c: +extern deh_section_t deh_section_text; +// deh_thing.c: +extern deh_section_t deh_section_thing; +// deh_weapon.c: +extern deh_section_t deh_section_weapon; + +// +// List of section types: +// + +deh_section_t *deh_section_types[] = +{ + &deh_section_ammo, + &deh_section_cheat, + &deh_section_frame, + &deh_section_misc, + &deh_section_pointer, + &deh_section_sound, + &deh_section_text, + &deh_section_thing, + &deh_section_weapon, + NULL +}; + diff --git a/src/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/src/strife/.gitignore b/src/strife/.gitignore index d7e732ad..973a0073 100644 --- a/src/strife/.gitignore +++ b/src/strife/.gitignore @@ -5,3 +5,5 @@ Makefile.in chocolate-doom chocolate-server *.exe +tags +TAGS diff --git a/src/strife/Makefile.am b/src/strife/Makefile.am index 85f8b764..c0e930cb 100644 --- a/src/strife/Makefile.am +++ b/src/strife/Makefile.am @@ -63,15 +63,11 @@ wi_stuff.c wi_stuff.h FEATURE_DEHACKED_SOURCE_FILES = \ deh_ammo.c \ deh_cheat.c \ -deh_defs.h \ +deh_strife.c \ deh_frame.c \ -deh_io.c deh_io.h \ -deh_main.c deh_main.h \ -deh_mapping.c deh_mapping.h \ deh_misc.c deh_misc.h \ deh_ptr.c \ deh_sound.c \ -deh_text.c \ deh_thing.c \ deh_weapon.c diff --git a/src/strife/deh_defs.h b/src/strife/deh_defs.h deleted file mode 100644 index e7b76182..00000000 --- a/src/strife/deh_defs.h +++ /dev/null @@ -1,68 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Definitions for use in the dehacked code -// -//----------------------------------------------------------------------------- - -#ifndef DEH_DEFS_H -#define DEH_DEFS_H - -#include "md5.h" - -typedef struct deh_context_s deh_context_t; -typedef struct deh_section_s deh_section_t; -typedef void (*deh_section_init_t)(void); -typedef void *(*deh_section_start_t)(deh_context_t *context, char *line); -typedef void (*deh_section_end_t)(deh_context_t *context, void *tag); -typedef void (*deh_line_parser_t)(deh_context_t *context, char *line, void *tag); -typedef void (*deh_md5_hash_t)(md5_context_t *context); - -struct deh_section_s -{ - char *name; - - // Called on startup to initialize code - - deh_section_init_t init; - - // This is called when a new section is started. The pointer - // returned is used as a tag for the following calls. - - deh_section_start_t start; - - // This is called for each line in the section - - deh_line_parser_t line_parser; - - // This is called at the end of the section for any cleanup - - deh_section_end_t end; - - // Called when generating an MD5 sum of the dehacked state - - deh_md5_hash_t md5_hash; -}; - -#endif /* #ifndef DEH_DEFS_H */ - - diff --git a/src/strife/deh_io.c b/src/strife/deh_io.c deleted file mode 100644 index 3386a6fa..00000000 --- a/src/strife/deh_io.c +++ /dev/null @@ -1,211 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Dehacked I/O code (does all reads from dehacked files) -// -//----------------------------------------------------------------------------- - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "i_system.h" -#include "z_zone.h" - -#include "deh_defs.h" -#include "deh_io.h" - -struct deh_context_s -{ - FILE *stream; - char *filename; - int linenum; - boolean last_was_newline; - char *readbuffer; - int readbuffer_size; -}; - -// Open a dehacked file for reading -// Returns NULL if open failed - -deh_context_t *DEH_OpenFile(char *filename) -{ - FILE *fstream; - deh_context_t *context; - - fstream = fopen(filename, "r"); - - if (fstream == NULL) - return NULL; - - context = Z_Malloc(sizeof(*context), PU_STATIC, NULL); - context->stream = fstream; - - // Initial read buffer size of 128 bytes - - context->readbuffer_size = 128; - context->readbuffer = Z_Malloc(context->readbuffer_size, PU_STATIC, NULL); - context->filename = filename; - context->linenum = 0; - context->last_was_newline = true; - - return context; -} - -// Close dehacked file - -void DEH_CloseFile(deh_context_t *context) -{ - fclose(context->stream); - Z_Free(context->readbuffer); - Z_Free(context); -} - -// Reads a single character from a dehacked file - -int DEH_GetChar(deh_context_t *context) -{ - int result; - - // Read characters, but ignore carriage returns - // Essentially this is a DOS->Unix conversion - - do - { - if (feof(context->stream)) - { - // end of file - - result = -1; - } - else - { - result = fgetc(context->stream); - } - - } while (result == '\r'); - - // Track the current line number - - if (context->last_was_newline) - { - ++context->linenum; - } - - context->last_was_newline = result == '\n'; - - return result; -} - -// Increase the read buffer size - -static void IncreaseReadBuffer(deh_context_t *context) -{ - char *newbuffer; - int newbuffer_size; - - newbuffer_size = context->readbuffer_size * 2; - newbuffer = Z_Malloc(newbuffer_size, PU_STATIC, NULL); - - memcpy(newbuffer, context->readbuffer, context->readbuffer_size); - - Z_Free(context->readbuffer); - - context->readbuffer = newbuffer; - context->readbuffer_size = newbuffer_size; -} - -// Read a whole line - -char *DEH_ReadLine(deh_context_t *context) -{ - int c; - int pos; - - for (pos = 0;;) - { - c = DEH_GetChar(context); - - if (c < 0) - { - // end of file - - return NULL; - } - - // cope with lines of any length: increase the buffer size - - if (pos >= context->readbuffer_size) - { - IncreaseReadBuffer(context); - } - - if (c == '\n') - { - // end of line: a full line has been read - - context->readbuffer[pos] = '\0'; - break; - } - else if (c != '\0') - { - // normal character; don't allow NUL characters to be - // added. - - context->readbuffer[pos] = (char) c; - ++pos; - } - } - - return context->readbuffer; -} - -void DEH_Warning(deh_context_t *context, char *msg, ...) -{ - va_list args; - - va_start(args, msg); - - fprintf(stderr, "%s:%i: warning: ", context->filename, context->linenum); - vfprintf(stderr, msg, args); - fprintf(stderr, "\n"); - - va_end(args); -} - -void DEH_Error(deh_context_t *context, char *msg, ...) -{ - va_list args; - - va_start(args, msg); - - fprintf(stderr, "%s:%i: ", context->filename, context->linenum); - vfprintf(stderr, msg, args); - fprintf(stderr, "\n"); - - va_end(args); - - I_Error("Error parsing dehacked file"); -} - - diff --git a/src/strife/deh_main.c b/src/strife/deh_main.c deleted file mode 100644 index 63cae460..00000000 --- a/src/strife/deh_main.c +++ /dev/null @@ -1,423 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Main dehacked code -// -//----------------------------------------------------------------------------- - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> - -#include "doomtype.h" -#include "d_iwad.h" -#include "m_argv.h" - -#include "deh_defs.h" -#include "deh_io.h" - -static char *deh_signatures[] = -{ - "Patch File for DeHackEd v2.3", - "Patch File for DeHackEd v3.0", -}; - -// deh_ammo.c: -extern deh_section_t deh_section_ammo; -// deh_cheat.c: -extern deh_section_t deh_section_cheat; -// deh_frame.c: -extern deh_section_t deh_section_frame; -// deh_misc.c: -extern deh_section_t deh_section_misc; -// deh_ptr.c: -extern deh_section_t deh_section_pointer; -// deh_sound.c -extern deh_section_t deh_section_sound; -// deh_text.c: -extern deh_section_t deh_section_text; -// deh_thing.c: -extern deh_section_t deh_section_thing; -// deh_weapon.c: -extern deh_section_t deh_section_weapon; - -// If true, we can do long string replacements. - -boolean deh_allow_long_strings = false; - -// If true, we can do cheat replacements longer than the originals. - -boolean deh_allow_long_cheats = false; - -// If false, dehacked cheat replacements are ignored. - -boolean deh_apply_cheats = true; - -// -// List of section types: -// - -static deh_section_t *section_types[] = -{ - &deh_section_ammo, - &deh_section_cheat, - &deh_section_frame, - &deh_section_misc, - &deh_section_pointer, - &deh_section_sound, - &deh_section_text, - &deh_section_thing, - &deh_section_weapon, -}; - -void DEH_Checksum(md5_digest_t digest) -{ - md5_context_t md5_context; - unsigned int i; - - MD5_Init(&md5_context); - - for (i=0; i<arrlen(section_types); ++i) - { - if (section_types[i]->md5_hash != NULL) - { - section_types[i]->md5_hash(&md5_context); - } - } - - MD5_Final(digest, &md5_context); -} - -// Called on startup to call the Init functions - -static void InitializeSections(void) -{ - unsigned int i; - - for (i=0; i<arrlen(section_types); ++i) - { - if (section_types[i]->init != NULL) - { - section_types[i]->init(); - } - } -} - -// Given a section name, get the section structure which corresponds - -static deh_section_t *GetSectionByName(char *name) -{ - unsigned int i; - - for (i=0; i<arrlen(section_types); ++i) - { - if (!strcasecmp(section_types[i]->name, name)) - { - return section_types[i]; - } - } - - return NULL; -} - -// Is the string passed just whitespace? - -static boolean IsWhitespace(char *s) -{ - for (; *s; ++s) - { - if (!isspace(*s)) - return false; - } - - return true; -} - -// Strip whitespace from the start and end of a string - -static char *CleanString(char *s) -{ - char *strending; - - // Leading whitespace - - while (*s && isspace(*s)) - ++s; - - // Trailing whitespace - - strending = s + strlen(s) - 1; - - while (strlen(s) > 0 && isspace(*strending)) - { - *strending = '\0'; - --strending; - } - - return s; -} - -// This pattern is used a lot of times in different sections, -// an assignment is essentially just a statement of the form: -// -// Variable Name = Value -// -// The variable name can include spaces or any other characters. -// The string is split on the '=', essentially. -// -// Returns true if read correctly - -boolean DEH_ParseAssignment(char *line, char **variable_name, char **value) -{ - char *p; - - // find the equals - - p = strchr(line, '='); - - if (p == NULL && p-line > 2) - { - return false; - } - - // variable name at the start - // turn the '=' into a \0 to terminate the string here - - *p = '\0'; - *variable_name = CleanString(line); - - // value immediately follows the '=' - - *value = CleanString(p+1); - - return true; -} - -static boolean CheckSignatures(deh_context_t *context) -{ - size_t i; - char *line; - - // Read the first line - - line = DEH_ReadLine(context); - - if (line == NULL) - { - return false; - } - - // Check all signatures to see if one matches - - for (i=0; i<arrlen(deh_signatures); ++i) - { - if (!strcmp(deh_signatures[i], line)) - { - return true; - } - } - - return false; -} - -// Parses a comment string in a dehacked file. - -static void DEH_ParseComment(char *comment) -{ - // Allow comments containing this special value to allow string - // replacements longer than those permitted by DOS dehacked. - // This allows us to use a dehacked patch for doing string - // replacements for emulating Chex Quest. - // - // If you use this, your dehacked patch may not work in Vanilla - // Doom. - - if (strstr(comment, "*allow-long-strings*") != NULL) - { - deh_allow_long_strings = true; - } - - // Allow magic comments to allow longer cheat replacements than - // those permitted by DOS dehacked. This is also for Chex - // Quest. - - if (strstr(comment, "*allow-long-cheats*") != NULL) - { - deh_allow_long_cheats = true; - } -} - -// Parses a dehacked file by reading from the context - -static void DEH_ParseContext(deh_context_t *context) -{ - deh_section_t *current_section = NULL; - char section_name[20]; - void *tag = NULL; - char *line; - - // Read the header and check it matches the signature - - if (!CheckSignatures(context)) - { - DEH_Error(context, "This is not a valid dehacked patch file!"); - } - - deh_allow_long_strings = false; - deh_allow_long_cheats = false; - - // Read the file - - for (;;) - { - // read a new line - - line = DEH_ReadLine(context); - - // end of file? - - if (line == NULL) - return; - - while (line[0] != '\0' && isspace(line[0])) - ++line; - - if (line[0] == '#') - { - // comment - - DEH_ParseComment(line); - continue; - } - - if (IsWhitespace(line)) - { - if (current_section != NULL) - { - // end of section - - if (current_section->end != NULL) - { - current_section->end(context, tag); - } - - //printf("end %s tag\n", current_section->name); - current_section = NULL; - } - } - else - { - if (current_section != NULL) - { - // parse this line - - current_section->line_parser(context, line, tag); - } - else - { - // possibly the start of a new section - - sscanf(line, "%19s", section_name); - - current_section = GetSectionByName(section_name); - - if (current_section != NULL) - { - tag = current_section->start(context, line); - //printf("started %s tag\n", section_name); - } - else - { - //printf("unknown section name %s\n", section_name); - } - } - } - } -} - -// Parses a dehacked file - -int DEH_LoadFile(char *filename) -{ - deh_context_t *context; - - printf(" loading %s\n", filename); - - context = DEH_OpenFile(filename); - - if (context == NULL) - { - fprintf(stderr, "DEH_LoadFile: Unable to open %s\n", filename); - return 0; - } - - DEH_ParseContext(context); - - DEH_CloseFile(context); - - return 1; -} - -// Checks the command line for -deh argument - -void DEH_Init(void) -{ - char *filename; - int p; - - InitializeSections(); - - //! - // @category mod - // - // Ignore cheats in dehacked files. - // - - if (M_CheckParm("-nocheats") > 0) - { - deh_apply_cheats = false; - } - - //! - // @arg <files> - // @category mod - // - // Load the given dehacked patch(es) - // - - p = M_CheckParm("-deh"); - - if (p > 0) - { - ++p; - - while (p < myargc && myargv[p][0] != '-') - { - filename = D_TryFindWADByName(myargv[p]); - DEH_LoadFile(filename); - ++p; - } - } -} - - diff --git a/src/strife/deh_mapping.c b/src/strife/deh_mapping.c deleted file mode 100644 index b215b128..00000000 --- a/src/strife/deh_mapping.c +++ /dev/null @@ -1,133 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Dehacked "mapping" code -// Allows the fields in structures to be mapped out and accessed by -// name -// -//----------------------------------------------------------------------------- - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "doomtype.h" -#include "i_system.h" -#include "deh_mapping.h" - -// -// Set the value of a particular field in a structure by name -// - -boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, - void *structptr, char *name, int value) -{ - int i; - - for (i=0; mapping->entries[i].name != NULL; ++i) - { - deh_mapping_entry_t *entry = &mapping->entries[i]; - - if (!strcasecmp(entry->name, name)) - { - void *location; - - if (entry->location == NULL) - { - DEH_Warning(context, "Field '%s' is unsupported", name); - return false; - } - - location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base); - - // printf("Setting %p::%s to %i (%i bytes)\n", - // structptr, name, value, entry->size); - - switch (entry->size) - { - case 1: - * ((uint8_t *) location) = value; - break; - case 2: - * ((uint16_t *) location) = value; - break; - case 4: - * ((uint32_t *) location) = value; - break; - default: - DEH_Error(context, "Unknown field type for '%s' (BUG)", name); - return false; - } - - return true; - } - } - - // field with this name not found - - DEH_Warning(context, "Field named '%s' not found", name); - - return false; -} - -void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping, - void *structptr) -{ - int i; - - // Go through each mapping - - for (i=0; mapping->entries[i].name != NULL; ++i) - { - deh_mapping_entry_t *entry = &mapping->entries[i]; - void *location; - - if (entry->location == NULL) - { - // Unsupported field - - continue; - } - - // Add in data for this field - - location = (uint8_t *)structptr + ((uint8_t *)entry->location - (uint8_t *)mapping->base); - - switch (entry->size) - { - case 1: - MD5_UpdateInt32(context, *((uint8_t *) location)); - break; - case 2: - MD5_UpdateInt32(context, *((uint16_t *) location)); - break; - case 4: - MD5_UpdateInt32(context, *((uint32_t *) location)); - break; - default: - I_Error("Unknown dehacked mapping field type for '%s' (BUG)", - entry->name); - break; - } - } -} - diff --git a/src/strife/deh_mapping.h b/src/strife/deh_mapping.h deleted file mode 100644 index 4862dec9..00000000 --- a/src/strife/deh_mapping.h +++ /dev/null @@ -1,90 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Dehacked "mapping" code -// Allows the fields in structures to be mapped out and accessed by -// name -// -//----------------------------------------------------------------------------- - -#ifndef DEH_MAPPING_H -#define DEH_MAPPING_H - -#include "doomtype.h" -#include "deh_io.h" -#include "md5.h" - -#define DEH_BEGIN_MAPPING(mapping_name, structname) \ - static structname deh_mapping_base; \ - static deh_mapping_t mapping_name = \ - { \ - &deh_mapping_base, \ - { - -#define DEH_MAPPING(deh_name, fieldname) \ - {deh_name, &deh_mapping_base.fieldname, \ - sizeof(deh_mapping_base.fieldname)}, - -#define DEH_UNSUPPORTED_MAPPING(deh_name) \ - {deh_name, NULL, -1}, - -#define DEH_END_MAPPING \ - {NULL, NULL, -1} \ - } \ - }; - - - -#define MAX_MAPPING_ENTRIES 32 - -typedef struct deh_mapping_s deh_mapping_t; -typedef struct deh_mapping_entry_s deh_mapping_entry_t; - -struct deh_mapping_entry_s -{ - // field name - - char *name; - - // location relative to the base in the deh_mapping_t struct - // If this is NULL, it is an unsupported mapping - - void *location; - - // field size - - int size; -}; - -struct deh_mapping_s -{ - void *base; - deh_mapping_entry_t entries[MAX_MAPPING_ENTRIES]; -}; - -boolean DEH_SetMapping(deh_context_t *context, deh_mapping_t *mapping, - void *structptr, char *name, int value); -void DEH_StructMD5Sum(md5_context_t *context, deh_mapping_t *mapping, - void *structptr); - -#endif /* #ifndef DEH_MAPPING_H */ - diff --git a/src/strife/deh_strife.c b/src/strife/deh_strife.c new file mode 100644 index 00000000..c9a7a73b --- /dev/null +++ b/src/strife/deh_strife.c @@ -0,0 +1,74 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2005 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- +// +// Top-level dehacked definitions for Strife dehacked (sehacked) +// +//----------------------------------------------------------------------------- + +#include <stdlib.h> +#include "deh_defs.h" +#include "deh_main.h" + +char *deh_signatures[] = +{ + "Patch File for DeHackEd v2.3", + "Patch File for DeHackEd v3.0", + NULL +}; + +// deh_ammo.c: +extern deh_section_t deh_section_ammo; +// deh_cheat.c: +extern deh_section_t deh_section_cheat; +// deh_frame.c: +extern deh_section_t deh_section_frame; +// deh_misc.c: +extern deh_section_t deh_section_misc; +// deh_ptr.c: +extern deh_section_t deh_section_pointer; +// deh_sound.c +extern deh_section_t deh_section_sound; +// deh_text.c: +extern deh_section_t deh_section_text; +// deh_thing.c: +extern deh_section_t deh_section_thing; +// deh_weapon.c: +extern deh_section_t deh_section_weapon; + +// +// List of section types: +// + +deh_section_t *deh_section_types[] = +{ + &deh_section_ammo, + &deh_section_cheat, + &deh_section_frame, + &deh_section_misc, + &deh_section_pointer, + &deh_section_sound, + &deh_section_text, + &deh_section_thing, + &deh_section_weapon, + NULL +}; + diff --git a/src/strife/deh_text.c b/src/strife/deh_text.c deleted file mode 100644 index 31e23db2..00000000 --- a/src/strife/deh_text.c +++ /dev/null @@ -1,127 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright(C) 2005 Simon Howard -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. -// -//----------------------------------------------------------------------------- -// -// Parses Text substitution sections in dehacked files -// -//----------------------------------------------------------------------------- - -#include <stdio.h> -#include <string.h> - -#include "doomtype.h" - -#include "z_zone.h" - -#include "deh_defs.h" -#include "deh_io.h" -#include "deh_main.h" - -// Given a string length, find the maximum length of a -// string that can replace it. - -static int TXT_MaxStringLength(int len) -{ - // Enough bytes for the string and the NUL terminator - - len += 1; - - // All strings in doom.exe are on 4-byte boundaries, so we may be able - // to support a slightly longer string. - // Extend up to the next 4-byte boundary - - len += (4 - (len % 4)) % 4; - - // Less one for the NUL terminator. - - return len - 1; -} - -static void *DEH_TextStart(deh_context_t *context, char *line) -{ - char *from_text, *to_text; - int fromlen, tolen; - int i; - - if (sscanf(line, "Text %i %i", &fromlen, &tolen) != 2) - { - DEH_Warning(context, "Parse error on section start"); - return NULL; - } - - // Only allow string replacements that are possible in Vanilla Doom. - // Chocolate Doom is unforgiving! - - if (!deh_allow_long_strings && tolen > TXT_MaxStringLength(fromlen)) - { - DEH_Error(context, "Replacement string is longer than the maximum " - "possible in doom.exe"); - return NULL; - } - - from_text = Z_Malloc(fromlen + 1, PU_STATIC, NULL); - to_text = Z_Malloc(tolen + 1, PU_STATIC, NULL); - - // read in the "from" text - - for (i=0; i<fromlen; ++i) - { - int c; - - c = DEH_GetChar(context); - - from_text[i] = c; - } - - from_text[fromlen] = '\0'; - - // read in the "to" text - - for (i=0; i<tolen; ++i) - { - int c; - - c = DEH_GetChar(context); - - to_text[i] = c; - } - to_text[tolen] = '\0'; - - DEH_AddStringReplacement(from_text, to_text); - - return NULL; -} - -static void DEH_TextParseLine(deh_context_t *context, char *line, void *tag) -{ - // not used -} - -deh_section_t deh_section_text = -{ - "Text", - NULL, - DEH_TextStart, - DEH_TextParseLine, - NULL, - NULL, -}; - diff --git a/src/strife/g_game.c b/src/strife/g_game.c index 35bf4d74..8d0e4503 100644 --- a/src/strife/g_game.c +++ b/src/strife/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/strife/hu_stuff.c b/src/strife/hu_stuff.c index a106978e..ca74ce92 100644 --- a/src/strife/hu_stuff.c +++ b/src/strife/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/strife/p_map.c b/src/strife/p_map.c index 3f88aabc..925e4398 100644 --- a/src/strife/p_map.c +++ b/src/strife/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/strife/p_setup.c b/src/strife/p_setup.c index 5cf7a628..2a3a8f85 100644 --- a/src/strife/p_setup.c +++ b/src/strife/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/strife/p_sight.c b/src/strife/p_sight.c index e192567b..79c1bb1d 100644 --- a/src/strife/p_sight.c +++ b/src/strife/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/strife/st_stuff.c b/src/strife/st_stuff.c index e6ef0828..160244ce 100644 --- a/src/strife/st_stuff.c +++ b/src/strife/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/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 |