diff options
author | Simon Howard | 2011-02-12 18:42:10 +0000 |
---|---|---|
committer | Simon Howard | 2011-02-12 18:42:10 +0000 |
commit | 516a7028994df6718289a7e3db4d07a45c95466b (patch) | |
tree | cf974cb4bd38b8e9d0101a41263b42b8c87e96c7 | |
parent | a15ba75736d15409876c1f0a44fffc99adf1c192 (diff) | |
parent | a9996b41e954d85fde5ec5188bbf6a7f4df88011 (diff) | |
download | chocolate-doom-516a7028994df6718289a7e3db4d07a45c95466b.tar.gz chocolate-doom-516a7028994df6718289a7e3db4d07a45c95466b.tar.bz2 chocolate-doom-516a7028994df6718289a7e3db4d07a45c95466b.zip |
Merge from raven-branch. FEATURE_MULTIPLAYER has been disabled
temporarily until the netgame changes on raven-branch are finished.
Subversion-branch: /branches/strife-branch
Subversion-revision: 2259
103 files changed, 6095 insertions, 1211 deletions
@@ -1,3 +1,380 @@ +2011-01-02 17:45:24 fraggle + + Remove redundant package version label from top of OS X launcher + window. + +2011-01-02 02:49:20 fraggle + + Restore window title when changing video driver in setup tool (thanks + AlexXav). + +2011-01-02 02:31:20 fraggle + + Turn off dynamic window resizing feature on OS X, as it adds an ugly + resize handle to the corner of the window that overlaps the view of + the game. + +2010-12-28 16:43:41 fraggle + + Make demo loop handling of DEMO4 case depend on the executable version + being emulated: the Vanilla versions did not have any conditional + behavior based on gamemode/gamemission. This has the side effect of + causing the game to exit with an error when playing with Final Doom, + but this is Vanilla behavior. + +2010-12-25 22:42:40 fraggle + + Include NOT-BUGS in rpm packages. + +2010-12-25 21:51:24 fraggle + + Pass through all command line arguments specified to the setup tool to + the game, to match Vanilla behavior (thanks AlexXav). + +2010-12-25 21:04:10 fraggle + + Remove the -wart parameter (thanks Sander van Dijk). + +2010-12-25 20:55:30 fraggle + + Remove the 32 character limit on the lengths of filenames specified to + -record (thanks AlexXav). + +2010-12-19 20:15:09 fraggle + + Change setup tool skill level names to match Doom's "new game" menu + exactly (thanks AlexXav). + +2010-12-18 23:55:07 fraggle + + Add a M_CheckParmWithArgs function, that behaves like M_CheckParm but + also checks that extra options were provided on the command line + (thanks Sander van Dijk). + +2010-12-14 20:55:30 fraggle + + Check that an address is provided to the -query command line option + (thanks Sander van Dijk). + +2010-12-12 13:11:11 fraggle + + Add -privateserver and -servername options to chocolate-server + manpage. Add server registration option to setup tool (thanks + exp(x)). + +2010-12-10 23:56:32 fraggle + + Fix memory leak when dynamically resizing window in true color video + modes. + +2010-12-10 22:37:29 fraggle + + Fix build problem (thanks Proteh). + +2010-12-10 22:21:56 fraggle + + Remove "Error:" from the message displayed by I_Error, to match + Vanilla. + +2010-12-10 20:53:23 fraggle + + Update NEWS. + +2010-12-10 20:43:05 fraggle + + Change alignment of actions in a window's action area so that there is + equal space either side of the center widget. This is more + aesthetically pleasing. + +2010-12-10 20:31:46 fraggle + + Replace txt_widget_t#selectable with a callback function to query + whether the widget is selectable. This stops the table code from + selecting things that aren't really selectable - eg. empty tables, + scrollpanes containing unselectable widgets, etc. Fixes a bug with + the warp menu (thanks Proteh). + +2010-12-10 19:15:37 fraggle + + Add "warp" menu to the main menu of the setup tool, like Vanilla + setup.exe (thanks Proteh). + +2010-12-10 18:15:12 fraggle + + Fix typo (thanks Sander van Dijk). + +2010-12-10 17:53:50 fraggle + + Specify master server port explicitly, so that server registration + works when using -port. + +2010-12-07 23:13:34 rtc_marine + + - Update chocolate-server codeblocks project + +2010-12-07 22:35:17 fraggle + + Assign the oldest client to be the controller, not the first found in + the clients[] array. + +2010-12-06 23:37:27 fraggle + + Fix -solo-net to actually behave the same as other ports. + +2010-12-06 22:38:24 fraggle + + Rename -netdemo command line parameter to -solo-net, for consistency + with other ports (-netdemo is still recognised). + +2010-12-06 00:04:08 fraggle + + Update NEWS. + +2010-12-05 14:42:09 fraggle + + Allow textscreen font to be overridden using the TEXTSCREEN_FONT + command line variable. + +2010-12-04 20:56:04 fraggle + + Rename search command line options: -search to search the Internet, + -localsearch to search local LAN. + +2010-12-04 20:48:07 fraggle + + Add ping time to query output. + +2010-12-04 20:40:10 fraggle + + Fix formatting for -masterquery to match -search. + +2010-12-04 20:34:39 fraggle + + Fix bug when running with -server option. + +2010-12-02 21:34:51 fraggle + + Make multiple query attempts to servers before giving up. Display a + warning if the master server does not respond. + +2010-12-02 20:32:52 fraggle + + Add -servername parameter to allow the owner to change the name + returned in response to queries (thanks AlexMax). + +2010-12-02 20:11:24 fraggle + + More refactoring of querying code, to not be specific to the purpose + of printing out a list. + +2010-12-02 19:26:05 fraggle + + Refactor query code and add a -masterquery command line parameter to + query the master server. + +2010-12-02 18:23:09 fraggle + + Register servers with Internet master server. + +2010-11-30 21:52:38 fraggle + + Oops. + +2010-11-30 20:44:20 fraggle + + Remove "-debugfile" command line option and associated variable. + +2010-11-30 20:26:37 fraggle + + Update NEWS. + +2010-11-30 20:09:22 rtc_marine + + - Update codeblocks project + +2010-11-30 20:00:06 fraggle + + Add support for HACX v1.2 IWAD file. + +2010-11-30 01:08:59 fraggle + + Add NOT-BUGS file with some common Vanilla gotchas. + +2010-11-29 20:18:10 fraggle + + Auto-adjust the screen color depth if the configured color depth is + not supported by the hardware. + +2010-11-27 23:23:12 fraggle + + Add dropdown list to setup tool to select screen BPP. + +2010-11-27 19:39:14 fraggle + + When generating the texture name lookup hash table, add new entries to + the end of chains. This way, entries earlier in the texture list + trump later entries with the same name. This fixes a bug with the + wrong sky being shown in Spooky01.wad (thanks Porsche Monty). + +2010-11-27 15:36:43 fraggle + + Fix -timer / -avg options to work like Vanilla when playing demos. + +2010-11-26 18:56:45 fraggle + + In non-palettized boxed screen modes, don't update the border areas of + the screen. This is more CPU and memory efficient, and also fixes the + "flashing border" bug when palette flashes occur. + +2010-11-26 18:36:48 fraggle + + Turn double buffering on for non-palettized screen modes, as this may + be the cause of screen tearing reports. + +2010-11-24 23:34:18 fraggle + + Detect when running on Windows Vista or later, and switch to 32 bpp + screen mode. + +2010-11-24 22:43:37 fraggle + + Add configuration file parameter and command line option to specify + the screen pixel depth. + +2010-11-24 08:09:48 fraggle + + Add workaround to stop freezeups with old versions of SDL_mixer. + +2010-11-21 15:44:43 fraggle + + Add -8in32 command line parameter to make the game run in 32-bit color + mode, scaling up into an intermediate 8-bit buffer first. This should + help with the palette problems experienced by Windows Vista/7 users. + +2010-11-09 16:10:52 fraggle + + Update Python scripts to work in Python 3. + +2010-09-19 21:09:36 fraggle + + Read response file in binary mode, to fix incomplete response file + bug. + +2010-08-31 21:00:20 fraggle + + Add weapon cycling buttons to joystick button list. + +2010-08-31 20:59:24 fraggle + + Don't double OPL sample values, as it causes horrible things to happen + with the Heretic title screen music. + +2010-08-28 19:35:08 fraggle + + Update NEWS. + +2010-08-28 19:28:05 fraggle + + Include INSTALL file in distribution packages. + +2010-08-22 18:59:12 fraggle + + Shut up compiler warning. + +2010-08-22 02:21:27 fraggle + + Change span drawing functions to work the same as Vanilla, so that in + screenshots, floors and ceilings are pixel-perfect identical to + Vanilla Doom (thanks Porsche Monty). + +2010-08-21 19:49:20 fraggle + + Change default mouse acceleration in setup tool to match the game's + default. + +2010-08-21 18:47:24 fraggle + + "Bug fix". + +2010-08-20 14:01:29 fraggle + + Remove debug printf(). + +2010-08-20 13:20:58 fraggle + + Align memory allocated by zone memory system to 8 byte boundaries on + 64-bit machines. Possibly fixes problems on sparc64? + +2010-08-20 12:30:30 fraggle + + Extend mouse code to support up to 8 buttons (allows mouse wheel to be + used). + +2010-08-15 16:23:28 fraggle + + Fix volume multiply; DBOPL now generating output. + +2010-08-15 15:57:37 fraggle + + Hook DBOPL into OPL library and remove FMOPL. Does not generate any + sound yet. + +2010-08-13 19:42:52 fraggle + + Add C-converted version of DOSbox OPL emulator. + +2010-08-09 18:53:10 fraggle + + Add weapon cycling bindings for mouse and joystick buttons. Add + weapon cycling bindings to configuration file and setup tool. + +2010-08-07 18:23:09 fraggle + + Change back filter frequency. Add debug code to dump resampled sound + effects to WAV files. + +2010-08-07 17:07:00 fraggle + + Fix sound resampling low pass filter. + +2010-08-04 19:25:04 fraggle + + Initial code for previous/next weapon switching keys. + +2010-08-03 21:12:36 fraggle + + When in windowed mode, allow the screen size to be dynamically resized + by dragging the window borders. + +2010-07-31 20:25:17 fraggle + + Add multiplayer spy key binding. + +2010-07-28 21:39:07 fraggle + + Add config file parameter to set OPL I/O port. + +2010-07-17 01:33:57 fraggle + + Check for libm, to fix Fedora compile issues. + +2010-07-14 21:36:53 fraggle + + Set MACOSX_DEPLOYMENT_TARGET to target 10.4, so that the launcher will + work on older versions. + +2010-07-10 17:06:15 fraggle + + Update NEWS and ChangeLog, bump version number. + +2010-07-10 16:56:18 fraggle + + Add key bindings for multiplayer messaging. + +2010-07-10 16:27:52 fraggle + + Add key binding to change demo recording quit key. + 2010-05-30 04:03:44 fraggle Add INSTALL to all distribution packages, add note in README. diff --git a/Makefile.am b/Makefile.am index 97a18507..09fc5868 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,6 +53,7 @@ EXTRA_DIST= \ README.OPL \ TODO \ BUGS \ + NOT-BUGS \ rpm.spec MAINTAINERCLEANFILES = $(AUX_DIST_GEN) @@ -1,33 +1,121 @@ -1.5.0 (2010-??-??): +1.6.0 (2011-??-??): + + Bugs fixed: + * Menu navigation when using joystick/joypad (thanks Alexandre + Xavier). + * For configuration file value for shift keys, use scan code for + right shift, not left shift (thanks AlexXav). + * Default joystick buttons for the setup tool now match Vanilla + (thanks twipley). + + libtextscreen: + * It is now possible to type a '+' in input boxes (thanks + Alexandre Xavier). + +1.5.0 (2011-01-02): Big changes in this version: * The DOSbox OPL emulator (DBOPL) has been imported to replace the older FMOPL code. The quality of OPL emulation is now therefore much better. + * The game can now run in screen modes at any color depth (not + just 8-bit modes). This is mainly to work around problems with + Windows Vista/7, where 8-bit color modes don't always work + properly. + * Multiplayer servers now register themselves with an Internet + master server. Use the -search command line parameter to + find servers on the Internet to play on. You can also use + DoomSeeker (http://skulltag.net/doomseeker/) which supports + this functionality. * When running in windowed mode, it is now possible to dynamically resize the window by dragging the window borders. + * Names can be specified for servers with the -servername command + line parameter. * There are now keyboard, mouse and joystick bindings to cycle through available weapons, making play with joypads or mobile devices (ie. without a proper keyboard) much more practical. * There is now a key binding to change the multiplayer spy key (usually F12). - * There is now a configuration file parameter to set the OPL I/O - port, for cards that don't use port 0x388. + * The setup tool now has a "warp" button on the main menu, like + Vanilla setup.exe (thanks Proteh). * Up to 8 mouse buttons are now supported (including the mousewheel). + * A new command line parameter has been added (-solo-net) which + can be used to simulate being in a single player netgame. + * There is now a configuration file parameter to set the OPL I/O + port, for cards that don't use port 0x388. + * The Python scripts used for building Chocolate Doom now work + with Python 3 (but also continue to work with Python 2) + (thanks arin). + * There is now a NOT-BUGS file included that lists some common + Vanilla Doom bugs/limitations that you might encounter + (thanks to Sander van Dijk for feedback). + + Compatibility: + * The -timer and -avg options now work the same as Vanilla when + playing back demos (thanks xttl) + * A texture lookup bug was fixed that caused the wrong sky to be + displayed in Spooky01.wad (thanks Porsche Monty). + * The HacX v1.2 IWAD file is now supported, and can be used + standalone without the need for the Doom II IWAD (thanks + atyth). + * The I_Error function doesn't display "Error:" before the error + message, matching the Vanilla behavior. "Error" has also been + removed from the title of the dialog box that appears on + Windows when this happens. This is desirable as not all such + messages are actually errors (thanks Proteh). + * The setup tool now passes through all command line arguments + when launching the game (thanks AlexXav). + * Demo loop behavior (ie. whether to play DEMO4) now depends on + the version being emulated. When playing Final Doom the game + will exit unexpectedly as it tries to play the fourth demo - + this is Vanilla behaviour (thanks AlexXav). Bugs fixed: + * A workaround has been a bug in old versions of SDL_mixer + (v1.2.8 and earlier) that could cause the game to lock up. + Please upgrade to a newer version if you haven't already. * It is now possible to use OPL emulation at 11025Hz sound - sampling rate (thanks to the new OPL emulator). + sampling rate, due to the new OPL emulator (thanks Porsche + Monty). * The span renderer function (used for drawing floors and ceilings) now behaves the same as Vanilla Doom, so screenshots are pixel-perfect identical to Vanilla Doom (thanks Porsche Monty). * The zone memory system now aligns allocated memory to 8-byte boundaries on 64-bit systems, which may fix crashes on systems - such as sparc64. + such as sparc64 (thanks Ryan Freeman and Edd Barrett). * The configure script now checks for libm, fixing compile - problems on Fedora Linux. + problems on Fedora Linux (thanks Sander van Dijk). + * Sound distortion with certain music files when played back + using OPL (eg. Heretic title screen). + * Error in Windows when reading response files (thanks Porsche + Monty, xttl, Janizdreg). + * Windows Vista/7 8-bit color mode issues (the default is now to + run in 32-bit color depth on these versions) (thanks to + everybody who reported this and helped test the fix). + * Screen borders no longer flash when running on widescreen + monitors, if you choose a true-color screen mode (thanks + exp(x)). + * The controller player in a netgame is the first player to join, + instead of just being someone who gets lucky. + * Command line arguments that take an option now check that an + option is provided (thanks Sander van Dijk). + * Skill level names in the setup tool are now written the same as + they are on the in-game "new game" menu (thanks AlexXav). + * There is no longer a limit on the lengths of filenames provided + to the -record command line parameter (thanks AlexXav). + * Window title is not lost in setup tool when changing video + driver (thanks AlexXav). + + libtextscreen: + * The font used for the textscreen library can be forced by + setting the TEXTSCREEN_FONT environment variable to "small" or + "normal". + * Tables or scroll panes that don't contain any selectable widgets + are now themselves not selectable (thanks Proteh). + * The actions displayed at the bottom of windows are now laid out + in a more aesthetically pleasing way. 1.4.0 (2010-07-10): diff --git a/NOT-BUGS b/NOT-BUGS new file mode 100644 index 00000000..f7d22231 --- /dev/null +++ b/NOT-BUGS @@ -0,0 +1,135 @@ + +The aim of Chocolate Doom is to behave as closely to Vanilla Doom as +possible. As a result, you may experience problems that you would +also experience when using Vanilla Doom. These are not "bugs" as +Chocolate Doom is behaving as intended. + +This is not intended to be a comprehensive list of Vanilla Doom bugs. +For more information, consult the "engine bugs" page of the Doom Wiki. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game exits after title screen with message about game version == + +The game may exit after the title screen is shown, with a message like +the following: + + Demo is from a different game version! + (read 106, should be 109) + + *** You may need to upgrade your version of Doom to v1.9. *** + See: http://doomworld.com/files/patches.shtml + This appears to be v1.6/v1.666. + +This usually indicates that your IWAD file that you are using to play +the game (usually named doom.wad or doom2.wad) is out of date. +Chocolate Doom only supports the v1.9 IWAD file. + +To fix the problem, you must upgrade to the v1.9 IWAD file. The URL +in the message has downloadable upgrade patches that you can use to +upgrade. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game exits in demo loop when playing Final Doom == + +When playing with the Final Doom IWAD files (tnt.wad, plutonia.wad), +if you leave the game at the title screen to play through the demo +loop, it will eventually exit with the following error message: + + W_GetNumForName: demo4 not found! + +This is the same behavior as the Vanilla executables that were +bundled with Final Doom. When Ultimate Doom was developed, a fourth +demo was added to the demo loop, and this change was retained in the +Final Doom version of the executable. However, the Final Doom IWADs +do not include a fourth demo, so the game crashes. + +One way to work around this problem is to make the game emulate the +original (pre-Ultimate Doom) v1.9 executable. To do this, add the +command line argument "-gameversion 1.9" when running the game. +However, be aware this version does have some subtle differences that +will affect the playback of Final Doom demos (lost soul bouncing, +teleport behavior). + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game exits when accessing the options menu == + +The game may exit with the message "Bad V_DrawPatch" when accessing +the options menu, if you have your mouse sensitivity set high. + +The Doom options menu has a slider that allows the mouse sensitivity +to be controlled; however, it has only a very limited range. It is +common for experienced players to set a mouse sensitivity that is much +higher than what can be set via the options menu. The setup program +allows a larger range of values to be set. + +However, setting very high sensitivity values causes the game to exit +when accessing the options menu under Vanilla Doom. Because Chocolate +Doom aims to emulate Vanilla Doom as closely as possible, it does the +same thing. + +One solution to the problem is to set a lower mouse sensitivity. +Alternatively, all of the settings in the options menu can be +controlled through Doom's key bindings anyway: + + End game: F7 + Messages on/off: F8 + Graphic detail high/low: F5 + Screen size smaller/larger: -/+ + Sound volume menu: F4 + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game exits with "Savegame buffer overrun" when saving the game == + +If you are playing on a particularly large level, it is possible that +when you save the game, the game will quit with the message "Savegame +buffer overrun". + +Vanilla Doom has a limited size memory buffer that it uses for saving +games. If you are playing on a large level, the buffer may be too +small for the entire savegame to fit. Chocolate Doom allows the limit +to be disabled: in the setup tool, go to the "compatibility" menu and +disable the "Vanilla savegame limit" option. + +If this error happens to you, your game has not been lost! A file +named temp.dsg is saved; rename this to doomsav0.dsg to make it appear +in the first slot in the "load game" menu. (On Unix systems, you will +need to look in the .chocolate-doom/savegames directory in your home +directory) + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game ends suddenly when recording a demo == + +If you are recording a very long demo, the game may exit suddenly. +Vanilla Doom has a limited size memory buffer that it uses to save the +demo into. When the buffer is full, the game exits. You can tell if +this happens, as the demo file will be around 131,072 bytes in size. + +You can work around this by using the -maxdemo command line parameter +to specify a larger buffer size. Alternatively, the limit can be +disabled: in the setup tool, go to the compatibility menu and disable +the "Vanilla demo limit" option. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +== Game exits with a message about "visplanes" == + +The game may exit with one of these messages: + + R_FindPlane: no more visplanes + R_DrawPlanes: visplane overflow (129) + +This is known as the "visplane overflow" limit and is one of the most +well-known Vanilla Doom engine limits. You should only ever experience +this when trying to play an add-on level. The level you are trying to +play is too complex; it was most likely designed to work with a limit +removing source port. + +More information can be found here: + + http://rome.ro/lee_killough/editing/visplane.shtml + @@ -65,9 +65,13 @@ Here are some examples: You are encouraged to sign up and contribute any useful information you may have regarding the port! - * Chocolate Doom is not perfect. See the BUGS file for a list of - known issues. New bug reports can be submitted to the Chocolate - Doom bug tracker on Sourceforge. See: + * Chocolate Doom is not perfect. See the BUGS file for a list of + known issues. Because of the nature of the project, you may also + encounter Vanilla Doom bugs; these are intentionally present; see + the NOT-BUGS file for more information. + + New bug reports can be submitted to the Chocolate Doom bug tracker + on Sourceforge. See: http://sourceforge.net/projects/chocolate-doom diff --git a/codeblocks/config.h b/codeblocks/config.h index d092bf73..9026d398 100644 --- a/codeblocks/config.h +++ b/codeblocks/config.h @@ -9,19 +9,19 @@ #define PACKAGE_NAME "Chocolate Doom" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "Chocolate Doom 1.4.0" +#define PACKAGE_STRING "Chocolate Doom 1.5.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "chocolate-doom" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.4.0" +#define PACKAGE_VERSION "1.5.0" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "1.4.0" +#define VERSION "1.5.0" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ diff --git a/codeblocks/game-res.rc b/codeblocks/game-res.rc index eef24852..beef1242 100644 --- a/codeblocks/game-res.rc +++ b/codeblocks/game-res.rc @@ -1,21 +1,21 @@ 1 ICON "../data/doom.ico" 1 VERSIONINFO -PRODUCTVERSION 1,4,0,0 -FILEVERSION 1,4,0,0 +PRODUCTVERSION 1,5,0,0 +FILEVERSION 1,5,0,0 FILETYPE 1 { BLOCK "StringFileInfo" { BLOCK "040904E4" { - VALUE "FileVersion", "1.4.0" - VALUE "FileDescription", "1.4.0" + VALUE "FileVersion", "1.5.0" + VALUE "FileDescription", "1.5.0" VALUE "InternalName", "Chocolate-Doom" VALUE "CompanyName", "Chocolate-Doom" VALUE "LegalCopyright", "GNU General Public License" VALUE "ProductName", "Chocolate-Doom" - VALUE "ProductVersion", "1.4.0" + VALUE "ProductVersion", "1.5.0" } } } diff --git a/codeblocks/server.cbp b/codeblocks/server.cbp index a34a66dd..8c8adfb8 100644 --- a/codeblocks/server.cbp +++ b/codeblocks/server.cbp @@ -84,6 +84,10 @@ <Option compilerVar="CC" /> </Unit> <Unit filename="..\src\net_packet.h" /> + <Unit filename="..\src\net_query.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="..\src\net_query.h" /> <Unit filename="..\src\net_sdl.c"> <Option compilerVar="CC" /> </Unit> diff --git a/codeblocks/setup-res.rc b/codeblocks/setup-res.rc index f1602adb..b3812a74 100644 --- a/codeblocks/setup-res.rc +++ b/codeblocks/setup-res.rc @@ -3,21 +3,21 @@ CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "setup-manifest.xml" 1 VERSIONINFO -PRODUCTVERSION 1,4,0,0 -FILEVERSION 1,4,0,0 +PRODUCTVERSION 1,5,0,0 +FILEVERSION 1,5,0,0 FILETYPE 1 { BLOCK "StringFileInfo" { BLOCK "040904E4" { - VALUE "FileVersion", "1.4.0" + VALUE "FileVersion", "1.5.0" VALUE "FileDescription", "Chocolate-Doom Setup" VALUE "InternalName", "chocolate-setup" VALUE "CompanyName", "fraggle@gmail.com" VALUE "LegalCopyright", "GNU General Public License" VALUE "ProductName", "Chocolate-Doom Setup" - VALUE "ProductVersion", "1.4.0" + VALUE "ProductVersion", "1.5.0" } } } diff --git a/configure.in b/configure.in index 4bea1201..4e63d582 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(Chocolate Doom, 1.4.0, fraggle@gmail.com, chocolate-doom) +AC_INIT(Chocolate Doom, 1.5.0, fraggle@gmail.com, chocolate-doom) PACKAGE_SHORTDESC="Conservative Doom source port" PACKAGE_COPYRIGHT="Copyright (C) 1993-2010" diff --git a/data/convert-icon b/data/convert-icon index c651bc7f..30fade20 100755 --- a/data/convert-icon +++ b/data/convert-icon @@ -1,6 +1,4 @@ -#!/usr/bin/python -# -# $Id: convert-icon 704 2006-10-18 00:51:11Z fraggle $ +#!/usr/bin/env python # # Copyright(C) 2005 Simon Howard # @@ -29,7 +27,7 @@ import re try: import Image except ImportError: - print "WARNING: Could not update %s. Please install the Python Imaging library." % sys.argv[2] + print("WARNING: Could not update %s. Please install the Python Imaging library." % sys.argv[2]) sys.exit(0) @@ -71,4 +69,3 @@ def convert_image(filename, output_filename): convert_image(sys.argv[1], sys.argv[2]) - diff --git a/man/chocolate-server.6 b/man/chocolate-server.6 index 65d0a3fe..f37173f2 100644 --- a/man/chocolate-server.6 +++ b/man/chocolate-server.6 @@ -29,6 +29,12 @@ mean the netgame will simply not function at all. .TP \fB-port <n>\fR Use the specified UDP port for communications, instead of the default (2342). +.TP +\fB-privateserver\fR +Don't register with the global master server. +.TP +\fB-servername <name>\fR +Specify a name for the server. .SH SEE ALSO \fBchocolate-doom\fR(6), \fBchocolate-setup\fR(6) @@ -150,11 +150,8 @@ config_files = {} show_vanilla_options = True class Parameter: - def __cmp__(self, other): - if self.name < other.name: - return -1 - else: - return 1 + def __lt__(self, other): + return self.name < other.name def __init__(self): self.text = "" @@ -296,10 +293,10 @@ def add_parameter(param, line, config_file): # Is this documenting a command line parameter? - match = re.search('M_CheckParm\s*\(\s*"(.*?)"\s*\)', line) + match = re.search('M_CheckParm(WithArgs)?\s*\(\s*"(.*?)"', line) if match: - param.name = match.group(1) + param.name = match.group(2) categories[param.category].add_param(param) return @@ -389,7 +386,7 @@ def print_template(template_file, content): try: for line in f: line = line.replace("@content", content) - print line.rstrip() + print(line.rstrip()) finally: f.close() @@ -407,7 +404,7 @@ def wiki_output(targets, template): read_wikipages() for t in targets: - print t.wiki_output() + print(t.wiki_output()) def plaintext_output(targets, template_file): @@ -419,13 +416,13 @@ def plaintext_output(targets, template_file): print_template(template_file, content) def usage(): - print "Usage: %s [-V] [-c filename ]( -m | -w | -p ) <directory>" \ - % sys.argv[0] - print " -c : Provide documentation for the specified configuration file" - print " -m : Manpage output" - print " -w : Wikitext output" - print " -p : Plaintext output" - print " -V : Don't show Vanilla Doom options" + print("Usage: %s [-V] [-c filename ]( -m | -w | -p ) <directory>" \ + % sys.argv[0]) + print(" -c : Provide documentation for the specified configuration file") + print(" -m : Manpage output") + print(" -w : Wikitext output") + print(" -p : Plaintext output") + print(" -V : Don't show Vanilla Doom options") sys.exit(0) # Parse command line diff --git a/msvc/config.h b/msvc/config.h index 006d7c74..d91bd23b 100644 --- a/msvc/config.h +++ b/msvc/config.h @@ -11,16 +11,16 @@ #define PACKAGE_NAME "Chocolate Doom" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "Chocolate Doom 1.4.0" +#define PACKAGE_STRING "Chocolate Doom 1.5.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "chocolate-doom" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.4.0" +#define PACKAGE_VERSION "1.5.0" /* Version number of package */ -#define VERSION "1.4.0" +#define VERSION "1.5.0" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ diff --git a/msvc/win32.rc b/msvc/win32.rc index 94a35372..3371d993 100644 --- a/msvc/win32.rc +++ b/msvc/win32.rc @@ -32,21 +32,21 @@ #endif
1 VERSIONINFO
-PRODUCTVERSION 1,4,0,0
-FILEVERSION 1,4,0,0
+PRODUCTVERSION 1,5,0,0
+FILEVERSION 1,5,0,0
FILETYPE 1
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
- VALUE "FileVersion", "1.4.0"
- VALUE "FileDescription", "Chocolate Doom 1.4.0"
+ VALUE "FileVersion", "1.5.0"
+ VALUE "FileDescription", "Chocolate Doom 1.5.0"
VALUE "InternalName", "chocolate-doom"
VALUE "CompanyName", "fraggle@gmail.com"
VALUE "LegalCopyright", "GNU General Public License"
VALUE "ProductName", "Chocolate Doom"
- VALUE "ProductVersion", "1.4.0"
+ VALUE "ProductVersion", "1.5.0"
END
END
END
diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c index f6a3b229..5059fb5e 100644 --- a/opl/opl_sdl.c +++ b/opl/opl_sdl.c @@ -176,8 +176,8 @@ static void FillBuffer(int16_t *buffer, unsigned int nsamples) for (i=0; i<nsamples; ++i) { - buffer[i * 2] = (int16_t) (mix_buffer[i] * 2); - buffer[i * 2 + 1] = (int16_t) (mix_buffer[i] * 2); + buffer[i * 2] = (int16_t) mix_buffer[i]; + buffer[i * 2 + 1] = (int16_t) mix_buffer[i]; } } diff --git a/pkg/Makefile.am b/pkg/Makefile.am index 63da8f53..438a870a 100644 --- a/pkg/Makefile.am +++ b/pkg/Makefile.am @@ -5,8 +5,7 @@ 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/designable.nib \ osx/Resources/launcher.nib/keyedobjects.nib \ osx/GNUmakefile \ osx/Info.plist.in osx/Info-gnustep.plist.in \ diff --git a/pkg/config.make.in b/pkg/config.make.in index dc2d2888..27e44bd8 100644 --- a/pkg/config.make.in +++ b/pkg/config.make.in @@ -25,6 +25,7 @@ DOC_FILES = README \ INSTALL \ NEWS \ BUGS \ + NOT-BUGS \ CMDLINE \ TODO diff --git a/pkg/osx/LauncherManager.h b/pkg/osx/LauncherManager.h index e454ab4f..7e8c35cd 100644 --- a/pkg/osx/LauncherManager.h +++ b/pkg/osx/LauncherManager.h @@ -35,7 +35,6 @@ id launchButton; id commandLineArguments; - id packageLabel; } - (void) launch: (id)sender; diff --git a/pkg/osx/LauncherManager.m b/pkg/osx/LauncherManager.m index ae91ef4d..8c523ab4 100644 --- a/pkg/osx/LauncherManager.m +++ b/pkg/osx/LauncherManager.m @@ -327,7 +327,6 @@ static NSString *AppendQuotedFilename(NSString *str, NSString *fileName) - (void) awakeFromNib { - [self->packageLabel setStringValue: @PACKAGE_STRING]; [self->launcherWindow setTitle: @PACKAGE_NAME " Launcher"]; [self->launcherWindow center]; [self->launcherWindow setDefaultButtonCell: [self->launchButton cell]]; diff --git a/pkg/osx/Resources/launcher.nib/classes.nib b/pkg/osx/Resources/launcher.nib/classes.nib deleted file mode 100644 index 7efc837a..00000000 --- a/pkg/osx/Resources/launcher.nib/classes.nib +++ /dev/null @@ -1,47 +0,0 @@ -{ - 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/designable.nib b/pkg/osx/Resources/launcher.nib/designable.nib new file mode 100644 index 00000000..856ea06f --- /dev/null +++ b/pkg/osx/Resources/launcher.nib/designable.nib @@ -0,0 +1,2679 @@ +<?xml version="1.0" encoding="UTF-8"?> +<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10"> + <data> + <int key="IBDocument.SystemTarget">1060</int> + <string key="IBDocument.SystemVersion">10F569</string> + <string key="IBDocument.InterfaceBuilderVersion">823</string> + <string key="IBDocument.AppKitVersion">1038.29</string> + <string key="IBDocument.HIToolboxVersion">461.00</string> + <object class="NSMutableDictionary" key="IBDocument.PluginVersions"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="NS.object.0">823</string> + </object> + <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> + <bool key="EncodedWithXMLCoder">YES</bool> + <integer value="29"/> + <integer value="2"/> + <integer value="227"/> + </object> + <object class="NSArray" key="IBDocument.PluginDependencies"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + </object> + <object class="NSMutableDictionary" key="IBDocument.Metadata"> + <string key="NS.key.0">PluginDependencyRecalculationVersion</string> + <integer value="1" key="NS.object.0"/> + </object> + <object class="NSMutableArray" key="IBDocument.RootObjects" id="500532821"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSCustomObject" id="675889750"> + <object class="NSMutableString" key="NSClassName"> + <characters key="NS.bytes">NSApplication</characters> + </object> + </object> + <object class="NSCustomObject" id="379361643"> + <string key="NSClassName">FirstResponder</string> + </object> + <object class="NSCustomObject" id="226652452"> + <string key="NSClassName">NSApplication</string> + </object> + <object class="NSWindowTemplate" id="790120634"> + <int key="NSWindowStyleMask">7</int> + <int key="NSWindowBacking">2</int> + <string key="NSWindowRect">{{350, 488}, {530, 190}}</string> + <int key="NSWTFlags">1886912512</int> + <string key="NSWindowTitle">(Package Name) Launcher</string> + <string key="NSWindowClass">NSWindow</string> + <object class="NSMutableString" key="NSViewClass"> + <characters key="NS.bytes">View</characters> + </object> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> + <string key="NSWindowContentMinSize">{243.529, 107}</string> + <object class="NSView" key="NSWindowView" id="588857216"> + <reference key="NSNextResponder"/> + <int key="NSvFlags">256</int> + <object class="NSMutableArray" key="NSSubviews"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSTextField" id="233433370"> + <reference key="NSNextResponder" ref="588857216"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{17, 159}, {360, 11}}</string> + <reference key="NSSuperview" ref="588857216"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="840496048"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">272629760</int> + <string type="base64-UTF8" key="NSContents">U2VsZWN0IGEgZ2FtZToKA</string> + <object class="NSFont" key="NSSupport" id="22"> + <string key="NSName">LucidaGrande</string> + <double key="NSSize">9</double> + <int key="NSfFlags">3614</int> + </object> + <reference key="NSControlView" ref="233433370"/> + <object class="NSColor" key="NSBackgroundColor" id="77619338"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">controlColor</string> + <object class="NSColor" key="NSColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes> + </object> + </object> + <object class="NSColor" key="NSTextColor" id="206071849"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">controlTextColor</string> + <object class="NSColor" key="NSColor" id="773009915"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MAA</bytes> + </object> + </object> + </object> + </object> + <object class="NSPopUpButton" id="936658753"> + <reference key="NSNextResponder" ref="588857216"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{17, 127}, {259, 26}}</string> + <reference key="NSSuperview" ref="588857216"/> + <bool key="NSEnabled">YES</bool> + <object class="NSPopUpButtonCell" key="NSCell" id="968990884"> + <int key="NSCellFlags">-2076049856</int> + <int key="NSCellFlags2">2048</int> + <object class="NSFont" key="NSSupport" id="407649812"> + <string key="NSName">LucidaGrande</string> + <double key="NSSize">13</double> + <int key="NSfFlags">1044</int> + </object> + <reference key="NSControlView" ref="936658753"/> + <int key="NSButtonFlags">109199615</int> + <int key="NSButtonFlags2">1</int> + <object class="NSFont" key="NSAlternateImage" id="813720862"> + <string key="NSName">LucidaGrande</string> + <double key="NSSize">13</double> + <int key="NSfFlags">16</int> + </object> + <string key="NSAlternateContents"/> + <object class="NSMutableString" key="NSKeyEquivalent"> + <characters key="NS.bytes"/> + </object> + <int key="NSPeriodicDelay">400</int> + <int key="NSPeriodicInterval">75</int> + <object class="NSMenuItem" key="NSMenuItem" id="532676330"> + <reference key="NSMenu" ref="562767686"/> + <string key="NSTitle">Game name</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <int key="NSState">1</int> + <object class="NSCustomResource" key="NSOnImage" id="819247708"> + <string key="NSClassName">NSImage</string> + <string key="NSResourceName">NSMenuCheckmark</string> + </object> + <object class="NSCustomResource" key="NSMixedImage" id="94574589"> + <string key="NSClassName">NSImage</string> + <string key="NSResourceName">NSMenuMixedState</string> + </object> + <string key="NSAction">_popUpItemAction:</string> + <reference key="NSTarget" ref="968990884"/> + </object> + <bool key="NSMenuItemRespectAlignment">YES</bool> + <object class="NSMenu" key="NSMenu" id="562767686"> + <object class="NSMutableString" key="NSTitle"> + <characters key="NS.bytes">OtherViews</characters> + </object> + <object class="NSMutableArray" key="NSMenuItems"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="532676330"/> + </object> + </object> + <int key="NSPreferredEdge">3</int> + <bool key="NSUsesItemFromMenu">YES</bool> + <bool key="NSAltersState">YES</bool> + <int key="NSArrowPosition">1</int> + </object> + </object> + <object class="NSImageView" id="837745433"> + <reference key="NSNextResponder" ref="588857216"/> + <int key="NSvFlags">256</int> + <object class="NSMutableSet" key="NSDragTypes"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="set.sortedObjects"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>Apple PDF pasteboard type</string> + <string>Apple PICT pasteboard type</string> + <string>Apple PNG pasteboard type</string> + <string>NSFilenamesPboardType</string> + <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string> + <string>NeXT TIFF v4.0 pasteboard type</string> + </object> + </object> + <string key="NSFrame">{{382, 51}, {128, 128}}</string> + <reference key="NSSuperview" ref="588857216"/> + <bool key="NSEnabled">YES</bool> + <object class="NSImageCell" key="NSCell" id="606342952"> + <int key="NSCellFlags">130560</int> + <int key="NSCellFlags2">33554432</int> + <object class="NSCustomResource" key="NSContents"> + <string key="NSClassName">NSImage</string> + <string key="NSResourceName">128x128</string> + </object> + <int key="NSAlign">0</int> + <int key="NSScale">1</int> + <int key="NSStyle">0</int> + <bool key="NSAnimates">YES</bool> + </object> + <bool key="NSEditable">YES</bool> + </object> + <object class="NSButton" id="63012253"> + <reference key="NSNextResponder" ref="588857216"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{281, 129}, {93, 23}}</string> + <reference key="NSSuperview" ref="588857216"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="339458432"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Configure...</string> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="63012253"/> + <int key="NSButtonFlags">-2038021889</int> + <int key="NSButtonFlags2">32</int> + <reference key="NSAlternateImage" ref="813720862"/> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">400</int> + <int key="NSPeriodicInterval">75</int> + </object> + </object> + <object class="NSTextField" id="270224583"> + <reference key="NSNextResponder" ref="588857216"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{17, 100}, {360, 11}}</string> + <reference key="NSSuperview" ref="588857216"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="442641975"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">272629760</int> + <string type="base64-UTF8" key="NSContents">Q29tbWFuZCBsaW5lIGFyZ3VtZW50czoKA</string> + <reference key="NSSupport" ref="22"/> + <reference key="NSControlView" ref="270224583"/> + <reference key="NSBackgroundColor" ref="77619338"/> + <reference key="NSTextColor" ref="206071849"/> + </object> + </object> + <object class="NSTextField" id="165411811"> + <reference key="NSNextResponder" ref="588857216"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{20, 70}, {354, 22}}</string> + <reference key="NSSuperview" ref="588857216"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="263205275"> + <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="165411811"/> + <bool key="NSDrawsBackground">YES</bool> + <object class="NSColor" key="NSBackgroundColor" id="612330193"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">textBackgroundColor</string> + <object class="NSColor" key="NSColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MQA</bytes> + </object> + </object> + <object class="NSColor" key="NSTextColor" id="943265597"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">textColor</string> + <reference key="NSColor" ref="773009915"/> + </object> + </object> + </object> + <object class="NSButton" id="521193242"> + <reference key="NSNextResponder" ref="588857216"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{387, 12}, {129, 32}}</string> + <reference key="NSSuperview" ref="588857216"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="660416141"> + <int key="NSCellFlags">-2080244224</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Launch Game</string> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="521193242"/> + <int key="NSButtonFlags">-2038284033</int> + <int key="NSButtonFlags2">1</int> + <reference key="NSAlternateImage" ref="407649812"/> + <string key="NSAlternateContents"/> + <object class="NSMutableString" key="NSKeyEquivalent"> + <characters key="NS.bytes"/> + </object> + <int key="NSPeriodicDelay">200</int> + <int key="NSPeriodicInterval">25</int> + </object> + </object> + <object class="NSButton" id="858516582"> + <reference key="NSNextResponder" ref="588857216"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{14, 12}, {149, 32}}</string> + <reference key="NSSuperview" ref="588857216"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="139359493"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Run Setup Tool...</string> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="858516582"/> + <int key="NSButtonFlags">-2038284033</int> + <int key="NSButtonFlags2">1</int> + <reference key="NSAlternateImage" ref="407649812"/> + <string key="NSAlternateContents"/> + <object class="NSMutableString" key="NSKeyEquivalent"> + <characters key="NS.bytes"/> + </object> + <int key="NSPeriodicDelay">200</int> + <int key="NSPeriodicInterval">25</int> + </object> + </object> + </object> + <string key="NSFrameSize">{530, 190}</string> + <reference key="NSSuperview"/> + </object> + <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> + <string key="NSMinSize">{243.529, 129}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> + </object> + <object class="NSMenu" id="624798014"> + <string key="NSTitle">MainMenu</string> + <object class="NSMutableArray" key="NSMenuItems"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMenuItem" id="231654028"> + <reference key="NSMenu" ref="624798014"/> + <string key="NSTitle">Launcher</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + <string key="NSAction">submenuAction:</string> + <object class="NSMenu" key="NSSubmenu" id="499410461"> + <string key="NSTitle">Launcher</string> + <object class="NSMutableArray" key="NSMenuItems"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMenuItem" id="320960707"> + <reference key="NSMenu" ref="499410461"/> + <string key="NSTitle">About...</string> + <string key="NSKeyEquiv"/> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="329501564"> + <reference key="NSMenu" ref="499410461"/> + <bool key="NSIsDisabled">YES</bool> + <bool key="NSIsSeparator">YES</bool> + <string key="NSTitle"/> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="786583327"> + <reference key="NSMenu" ref="499410461"/> + <string key="NSTitle">IWAD configuration...</string> + <string key="NSKeyEquiv">,</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="461135404"> + <reference key="NSMenu" ref="499410461"/> + <string key="NSTitle">Command Prompt...</string> + <string key="NSKeyEquiv">t</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="594796138"> + <reference key="NSMenu" ref="499410461"/> + <bool key="NSIsDisabled">YES</bool> + <bool key="NSIsSeparator">YES</bool> + <string key="NSTitle"/> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="1021771665"> + <reference key="NSMenu" ref="499410461"/> + <string key="NSTitle">Services</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + <string key="NSAction">submenuAction:</string> + <object class="NSMenu" key="NSSubmenu" id="883685847"> + <object class="NSMutableString" key="NSTitle"> + <characters key="NS.bytes">Services</characters> + </object> + <object class="NSMutableArray" key="NSMenuItems"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <string key="NSName">_NSServicesMenu</string> + </object> + </object> + <object class="NSMenuItem" id="741321419"> + <reference key="NSMenu" ref="499410461"/> + <bool key="NSIsDisabled">YES</bool> + <bool key="NSIsSeparator">YES</bool> + <string key="NSTitle"/> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="156272785"> + <reference key="NSMenu" ref="499410461"/> + <string key="NSTitle">Hide</string> + <string key="NSKeyEquiv">h</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="770461341"> + <reference key="NSMenu" ref="499410461"/> + <string key="NSTitle">Hide Others</string> + <string key="NSKeyEquiv">h</string> + <int key="NSKeyEquivModMask">1572864</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="644979712"> + <reference key="NSMenu" ref="499410461"/> + <string key="NSTitle">Show All</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="276734846"> + <reference key="NSMenu" ref="499410461"/> + <bool key="NSIsDisabled">YES</bool> + <bool key="NSIsSeparator">YES</bool> + <string key="NSTitle"/> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="730606146"> + <reference key="NSMenu" ref="499410461"/> + <string key="NSTitle">Quit</string> + <string key="NSKeyEquiv">q</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + </object> + <string key="NSName">_NSAppleMenu</string> + </object> + </object> + <object class="NSMenuItem" id="729612487"> + <reference key="NSMenu" ref="624798014"/> + <string key="NSTitle">Edit</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + <string key="NSAction">submenuAction:</string> + <object class="NSMenu" key="NSSubmenu" id="324022003"> + <object class="NSMutableString" key="NSTitle"> + <characters key="NS.bytes">Edit</characters> + </object> + <object class="NSMutableArray" key="NSMenuItems"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMenuItem" id="495532942"> + <reference key="NSMenu" ref="324022003"/> + <string key="NSTitle">Undo</string> + <string key="NSKeyEquiv">z</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="47062370"> + <reference key="NSMenu" ref="324022003"/> + <string key="NSTitle">Redo</string> + <string key="NSKeyEquiv">Z</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="922159417"> + <reference key="NSMenu" ref="324022003"/> + <bool key="NSIsDisabled">YES</bool> + <bool key="NSIsSeparator">YES</bool> + <string key="NSTitle"/> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="463629067"> + <reference key="NSMenu" ref="324022003"/> + <string key="NSTitle">Cut</string> + <string key="NSKeyEquiv">x</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="854781678"> + <reference key="NSMenu" ref="324022003"/> + <string key="NSTitle">Copy</string> + <string key="NSKeyEquiv">c</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="140484273"> + <reference key="NSMenu" ref="324022003"/> + <string key="NSTitle">Paste</string> + <string key="NSKeyEquiv">v</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="252305464"> + <reference key="NSMenu" ref="324022003"/> + <string key="NSTitle">Delete</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="915916931"> + <reference key="NSMenu" ref="324022003"/> + <string key="NSTitle">Select All</string> + <string key="NSKeyEquiv">a</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + </object> + </object> + </object> + <object class="NSMenuItem" id="419477060"> + <reference key="NSMenu" ref="624798014"/> + <string key="NSTitle">Window</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + <string key="NSAction">submenuAction:</string> + <object class="NSMenu" key="NSSubmenu" id="893534477"> + <object class="NSMutableString" key="NSTitle"> + <characters key="NS.bytes">Window</characters> + </object> + <object class="NSMutableArray" key="NSMenuItems"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSMenuItem" id="105811130"> + <reference key="NSMenu" ref="893534477"/> + <string key="NSTitle">Minimize</string> + <string key="NSKeyEquiv">m</string> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="590253993"> + <reference key="NSMenu" ref="893534477"/> + <string key="NSTitle">Zoom</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="1009742520"> + <reference key="NSMenu" ref="893534477"/> + <bool key="NSIsDisabled">YES</bool> + <bool key="NSIsSeparator">YES</bool> + <string key="NSTitle"/> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + <object class="NSMenuItem" id="575456822"> + <reference key="NSMenu" ref="893534477"/> + <string key="NSTitle">Bring All to Front</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <reference key="NSOnImage" ref="819247708"/> + <reference key="NSMixedImage" ref="94574589"/> + </object> + </object> + <string key="NSName">_NSWindowsMenu</string> + </object> + </object> + </object> + <string key="NSName">_NSMainMenu</string> + </object> + <object class="NSCustomObject" id="590266459"> + <string key="NSClassName">LauncherManager</string> + </object> + <object class="NSCustomObject" id="938927474"> + <string key="NSClassName">IWADController</string> + </object> + <object class="NSWindowTemplate" id="193084417"> + <int key="NSWindowStyleMask">7</int> + <int key="NSWindowBacking">2</int> + <string key="NSWindowRect">{{377, 409}, {480, 316}}</string> + <int key="NSWTFlags">1886912512</int> + <string key="NSWindowTitle">IWAD configuration</string> + <object class="NSMutableString" key="NSWindowClass"> + <characters key="NS.bytes">NSWindow</characters> + </object> + <object class="NSMutableString" key="NSViewClass"> + <characters key="NS.bytes">View</characters> + </object> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> + <string key="NSWindowContentMinSize">{213, 107}</string> + <object class="NSView" key="NSWindowView" id="145141922"> + <reference key="NSNextResponder"/> + <int key="NSvFlags">256</int> + <object class="NSMutableArray" key="NSSubviews"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSTextField" id="348674481"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{17, 285}, {446, 11}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="522582983"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">272629760</int> + <string key="NSContents">Doom IWAD location (doom.wad):</string> + <reference key="NSSupport" ref="22"/> + <reference key="NSControlView" ref="348674481"/> + <reference key="NSBackgroundColor" ref="77619338"/> + <reference key="NSTextColor" ref="206071849"/> + </object> + </object> + <object class="NSTextField" id="215057262"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{20, 255}, {369, 22}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="596525351"> + <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="215057262"/> + <bool key="NSDrawsBackground">YES</bool> + <reference key="NSBackgroundColor" ref="612330193"/> + <reference key="NSTextColor" ref="943265597"/> + </object> + </object> + <object class="NSButton" id="410786529"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{397, 255}, {63, 23}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="673476660"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Set...</string> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="410786529"/> + <int key="NSButtonFlags">-2038021889</int> + <int key="NSButtonFlags2">32</int> + <reference key="NSAlternateImage" ref="813720862"/> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">400</int> + <int key="NSPeriodicInterval">75</int> + </object> + </object> + <object class="NSTextField" id="316721564"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{17, 236}, {446, 11}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="663066257"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">272629760</int> + <string key="NSContents">Doom II IWAD location (doom2.wad):</string> + <reference key="NSSupport" ref="22"/> + <reference key="NSControlView" ref="316721564"/> + <reference key="NSBackgroundColor" ref="77619338"/> + <reference key="NSTextColor" ref="206071849"/> + </object> + </object> + <object class="NSTextField" id="458378991"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{20, 206}, {369, 22}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="848829815"> + <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="458378991"/> + <bool key="NSDrawsBackground">YES</bool> + <reference key="NSBackgroundColor" ref="612330193"/> + <reference key="NSTextColor" ref="943265597"/> + </object> + </object> + <object class="NSButton" id="644218899"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{397, 206}, {63, 23}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="63361904"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Set...</string> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="644218899"/> + <int key="NSButtonFlags">-2038021889</int> + <int key="NSButtonFlags2">32</int> + <reference key="NSAlternateImage" ref="813720862"/> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">400</int> + <int key="NSPeriodicInterval">75</int> + </object> + </object> + <object class="NSTextField" id="179636494"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{17, 187}, {446, 11}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="84857374"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">272629760</int> + <string type="base64-UTF8" key="NSContents">RmluYWwgRG9vbTogVE5UOiBFdmlsdXRpb24gbG9jYXRpb24gKHRudC53YWQpOgo</string> + <reference key="NSSupport" ref="22"/> + <reference key="NSControlView" ref="179636494"/> + <reference key="NSBackgroundColor" ref="77619338"/> + <reference key="NSTextColor" ref="206071849"/> + </object> + </object> + <object class="NSTextField" id="1021143679"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{20, 157}, {369, 22}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="629867670"> + <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="1021143679"/> + <bool key="NSDrawsBackground">YES</bool> + <reference key="NSBackgroundColor" ref="612330193"/> + <reference key="NSTextColor" ref="943265597"/> + </object> + </object> + <object class="NSButton" id="539465960"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{397, 157}, {63, 23}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="979277836"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Set...</string> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="539465960"/> + <int key="NSButtonFlags">-2038021889</int> + <int key="NSButtonFlags2">32</int> + <reference key="NSAlternateImage" ref="813720862"/> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">400</int> + <int key="NSPeriodicInterval">75</int> + </object> + </object> + <object class="NSTextField" id="712311825"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{17, 138}, {446, 11}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="131918744"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">272629760</int> + <string type="base64-UTF8" key="NSContents">RmluYWwgRG9vbTogUGx1dG9uaWEgRXhwZXJpbWVudCBsb2NhdGlvbiAocGx1dG9uaWEud2FkKToKA</string> + <reference key="NSSupport" ref="22"/> + <reference key="NSControlView" ref="712311825"/> + <reference key="NSBackgroundColor" ref="77619338"/> + <reference key="NSTextColor" ref="206071849"/> + </object> + </object> + <object class="NSTextField" id="355049668"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{20, 108}, {369, 22}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="17259252"> + <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="355049668"/> + <bool key="NSDrawsBackground">YES</bool> + <reference key="NSBackgroundColor" ref="612330193"/> + <reference key="NSTextColor" ref="943265597"/> + </object> + </object> + <object class="NSButton" id="602477213"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{397, 108}, {63, 23}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="406066834"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Set...</string> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="602477213"/> + <int key="NSButtonFlags">-2038021889</int> + <int key="NSButtonFlags2">32</int> + <reference key="NSAlternateImage" ref="813720862"/> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">400</int> + <int key="NSPeriodicInterval">75</int> + </object> + </object> + <object class="NSTextField" id="452288864"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{17, 89}, {446, 11}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="969661180"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">272629760</int> + <string key="NSContents">Chex Quest IWAD location (chex.wad):</string> + <reference key="NSSupport" ref="22"/> + <reference key="NSControlView" ref="452288864"/> + <reference key="NSBackgroundColor" ref="77619338"/> + <reference key="NSTextColor" ref="206071849"/> + </object> + </object> + <object class="NSTextField" id="625273251"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{20, 59}, {369, 22}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="857754300"> + <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags2">272630784</int> + <string key="NSContents"/> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="625273251"/> + <bool key="NSDrawsBackground">YES</bool> + <reference key="NSBackgroundColor" ref="612330193"/> + <reference key="NSTextColor" ref="943265597"/> + </object> + </object> + <object class="NSButton" id="680095551"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{397, 59}, {63, 23}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="1012408786"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Set...</string> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="680095551"/> + <int key="NSButtonFlags">-2038021889</int> + <int key="NSButtonFlags2">32</int> + <reference key="NSAlternateImage" ref="813720862"/> + <string key="NSAlternateContents"/> + <string key="NSKeyEquivalent"/> + <int key="NSPeriodicDelay">400</int> + <int key="NSPeriodicInterval">75</int> + </object> + </object> + <object class="NSButton" id="658359713"> + <reference key="NSNextResponder" ref="145141922"/> + <int key="NSvFlags">256</int> + <string key="NSFrame">{{384, 12}, {82, 32}}</string> + <reference key="NSSuperview" ref="145141922"/> + <bool key="NSEnabled">YES</bool> + <object class="NSButtonCell" key="NSCell" id="235375789"> + <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags2">134217728</int> + <string key="NSContents">Close</string> + <reference key="NSSupport" ref="407649812"/> + <reference key="NSControlView" ref="658359713"/> + <int key="NSButtonFlags">-2038284033</int> + <int key="NSButtonFlags2">1</int> + <reference key="NSAlternateImage" ref="407649812"/> + <string key="NSAlternateContents"/> + <object class="NSMutableString" key="NSKeyEquivalent"> + <characters key="NS.bytes"/> + </object> + <int key="NSPeriodicDelay">200</int> + <int key="NSPeriodicInterval">25</int> + </object> + </object> + </object> + <string key="NSFrameSize">{480, 316}</string> + <reference key="NSSuperview"/> + </object> + <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> + <string key="NSMinSize">{213, 129}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> + </object> + <object class="NSCustomObject" id="805322722"> + <string key="NSClassName">IWADLocation</string> + </object> + <object class="NSCustomObject" id="328707004"> + <string key="NSClassName">IWADLocation</string> + </object> + <object class="NSCustomObject" id="808449249"> + <string key="NSClassName">IWADLocation</string> + </object> + <object class="NSCustomObject" id="645425571"> + <string key="NSClassName">IWADLocation</string> + </object> + <object class="NSCustomObject" id="142365428"> + <string key="NSClassName">IWADLocation</string> + </object> + <object class="NSCustomObject" id="825061065"> + <string key="NSClassName">AppController</string> + </object> + <object class="NSCustomObject" id="201870239"> + <string key="NSClassName">LauncherManager</string> + </object> + <object class="NSCustomObject" id="895790931"> + <string key="NSClassName">LauncherManager</string> + </object> + <object class="NSCustomObject" id="366010945"> + <string key="NSClassName">LauncherManager</string> + </object> + </object> + <object class="IBObjectContainer" key="IBDocument.Objects"> + <object class="NSMutableArray" key="connectionRecords"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">performMiniaturize:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="105811130"/> + </object> + <int key="connectionID">37</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">arrangeInFront:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="575456822"/> + </object> + <int key="connectionID">39</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">terminate:</string> + <reference key="source" ref="675889750"/> + <reference key="destination" ref="730606146"/> + </object> + <int key="connectionID">139</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">orderFrontStandardAboutPanel:</string> + <reference key="source" ref="675889750"/> + <reference key="destination" ref="320960707"/> + </object> + <int key="connectionID">142</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">hideOtherApplications:</string> + <reference key="source" ref="675889750"/> + <reference key="destination" ref="770461341"/> + </object> + <int key="connectionID">146</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">hide:</string> + <reference key="source" ref="675889750"/> + <reference key="destination" ref="156272785"/> + </object> + <int key="connectionID">152</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">unhideAllApplications:</string> + <reference key="source" ref="675889750"/> + <reference key="destination" ref="644979712"/> + </object> + <int key="connectionID">153</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">performZoom:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="590253993"/> + </object> + <int key="connectionID">198</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">launcherWindow</string> + <reference key="source" ref="590266459"/> + <reference key="destination" ref="790120634"/> + </object> + <int key="connectionID">207</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">commandLineArguments</string> + <reference key="source" ref="590266459"/> + <reference key="destination" ref="165411811"/> + </object> + <int key="connectionID">222</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">runSetup:</string> + <reference key="source" ref="590266459"/> + <reference key="destination" ref="858516582"/> + </object> + <int key="connectionID">223</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">launch:</string> + <reference key="source" ref="590266459"/> + <reference key="destination" ref="521193242"/> + </object> + <int key="connectionID">224</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">openConfigWindow:</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="63012253"/> + </object> + <int key="connectionID">226</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">locationConfigBox</string> + <reference key="source" ref="805322722"/> + <reference key="destination" ref="215057262"/> + </object> + <int key="connectionID">251</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">locationConfigBox</string> + <reference key="source" ref="328707004"/> + <reference key="destination" ref="458378991"/> + </object> + <int key="connectionID">252</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">locationConfigBox</string> + <reference key="source" ref="808449249"/> + <reference key="destination" ref="1021143679"/> + </object> + <int key="connectionID">253</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">locationConfigBox</string> + <reference key="source" ref="142365428"/> + <reference key="destination" ref="625273251"/> + </object> + <int key="connectionID">254</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">setButtonClicked:</string> + <reference key="source" ref="805322722"/> + <reference key="destination" ref="410786529"/> + </object> + <int key="connectionID">255</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">setButtonClicked:</string> + <reference key="source" ref="328707004"/> + <reference key="destination" ref="644218899"/> + </object> + <int key="connectionID">256</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">setButtonClicked:</string> + <reference key="source" ref="808449249"/> + <reference key="destination" ref="539465960"/> + </object> + <int key="connectionID">257</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">setButtonClicked:</string> + <reference key="source" ref="142365428"/> + <reference key="destination" ref="680095551"/> + </object> + <int key="connectionID">258</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">closeConfigWindow:</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="658359713"/> + </object> + <int key="connectionID">259</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">doom1</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="805322722"/> + </object> + <int key="connectionID">260</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">doom2</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="328707004"/> + </object> + <int key="connectionID">261</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">tnt</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="808449249"/> + </object> + <int key="connectionID">262</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">plutonia</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="645425571"/> + </object> + <int key="connectionID">263</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">chex</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="142365428"/> + </object> + <int key="connectionID">264</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">configWindow</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="193084417"/> + </object> + <int key="connectionID">265</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">iwadSelector</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="936658753"/> + </object> + <int key="connectionID">266</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">locationConfigBox</string> + <reference key="source" ref="645425571"/> + <reference key="destination" ref="355049668"/> + </object> + <int key="connectionID">267</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">openConfigWindow:</string> + <reference key="source" ref="938927474"/> + <reference key="destination" ref="786583327"/> + </object> + <int key="connectionID">268</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">iwadController</string> + <reference key="source" ref="590266459"/> + <reference key="destination" ref="938927474"/> + </object> + <int key="connectionID">269</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="675889750"/> + <reference key="destination" ref="825061065"/> + </object> + <int key="connectionID">271</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">launcherManager</string> + <reference key="source" ref="825061065"/> + <reference key="destination" ref="590266459"/> + </object> + <int key="connectionID">272</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">setButtonClicked:</string> + <reference key="source" ref="645425571"/> + <reference key="destination" ref="602477213"/> + </object> + <int key="connectionID">273</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">paste:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="140484273"/> + </object> + <int key="connectionID">306</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">delete:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="252305464"/> + </object> + <int key="connectionID">307</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">cut:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="463629067"/> + </object> + <int key="connectionID">310</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">undo:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="495532942"/> + </object> + <int key="connectionID">313</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">copy:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="854781678"/> + </object> + <int key="connectionID">315</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">selectAll:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="915916931"/> + </object> + <int key="connectionID">317</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">redo:</string> + <reference key="source" ref="379361643"/> + <reference key="destination" ref="47062370"/> + </object> + <int key="connectionID">318</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">openTerminal:</string> + <reference key="source" ref="590266459"/> + <reference key="destination" ref="461135404"/> + </object> + <int key="connectionID">321</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">launchButton</string> + <reference key="source" ref="590266459"/> + <reference key="destination" ref="521193242"/> + </object> + <int key="connectionID">322</int> + </object> + </object> + <object class="IBMutableOrderedSet" key="objectRecords"> + <object class="NSArray" key="orderedObjects"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBObjectRecord"> + <int key="objectID">0</int> + <object class="NSArray" key="object" id="0"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <reference key="children" ref="500532821"/> + <nil key="parent"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-2</int> + <reference key="object" ref="675889750"/> + <reference key="parent" ref="0"/> + <string key="objectName">File's Owner</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-1</int> + <reference key="object" ref="379361643"/> + <reference key="parent" ref="0"/> + <string key="objectName">First Responder</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">21</int> + <reference key="object" ref="790120634"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="588857216"/> + </object> + <reference key="parent" ref="0"/> + <string key="objectName">Launcher Window</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">2</int> + <reference key="object" ref="588857216"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="233433370"/> + <reference ref="936658753"/> + <reference ref="63012253"/> + <reference ref="270224583"/> + <reference ref="165411811"/> + <reference ref="837745433"/> + <reference ref="521193242"/> + <reference ref="858516582"/> + </object> + <reference key="parent" ref="790120634"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">209</int> + <reference key="object" ref="233433370"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="840496048"/> + </object> + <reference key="parent" ref="588857216"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">211</int> + <reference key="object" ref="936658753"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="968990884"/> + </object> + <reference key="parent" ref="588857216"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">216</int> + <reference key="object" ref="837745433"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="606342952"/> + </object> + <reference key="parent" ref="588857216"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">217</int> + <reference key="object" ref="63012253"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="339458432"/> + </object> + <reference key="parent" ref="588857216"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">218</int> + <reference key="object" ref="270224583"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="442641975"/> + </object> + <reference key="parent" ref="588857216"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">219</int> + <reference key="object" ref="165411811"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="263205275"/> + </object> + <reference key="parent" ref="588857216"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">220</int> + <reference key="object" ref="521193242"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="660416141"/> + </object> + <reference key="parent" ref="588857216"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">221</int> + <reference key="object" ref="858516582"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="139359493"/> + </object> + <reference key="parent" ref="588857216"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">29</int> + <reference key="object" ref="624798014"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="419477060"/> + <reference ref="231654028"/> + <reference ref="729612487"/> + </object> + <reference key="parent" ref="0"/> + <string key="objectName">MainMenu</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">19</int> + <reference key="object" ref="419477060"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="893534477"/> + </object> + <reference key="parent" ref="624798014"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">24</int> + <reference key="object" ref="893534477"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="575456822"/> + <reference ref="105811130"/> + <reference ref="1009742520"/> + <reference ref="590253993"/> + </object> + <reference key="parent" ref="419477060"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">5</int> + <reference key="object" ref="575456822"/> + <reference key="parent" ref="893534477"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">23</int> + <reference key="object" ref="105811130"/> + <reference key="parent" ref="893534477"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">92</int> + <reference key="object" ref="1009742520"/> + <reference key="parent" ref="893534477"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">197</int> + <reference key="object" ref="590253993"/> + <reference key="parent" ref="893534477"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">56</int> + <reference key="object" ref="231654028"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="499410461"/> + </object> + <reference key="parent" ref="624798014"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">57</int> + <reference key="object" ref="499410461"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="320960707"/> + <reference ref="786583327"/> + <reference ref="1021771665"/> + <reference ref="156272785"/> + <reference ref="730606146"/> + <reference ref="594796138"/> + <reference ref="741321419"/> + <reference ref="770461341"/> + <reference ref="276734846"/> + <reference ref="644979712"/> + <reference ref="329501564"/> + <reference ref="461135404"/> + </object> + <reference key="parent" ref="231654028"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">58</int> + <reference key="object" ref="320960707"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">129</int> + <reference key="object" ref="786583327"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">131</int> + <reference key="object" ref="1021771665"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="883685847"/> + </object> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">130</int> + <reference key="object" ref="883685847"/> + <reference key="parent" ref="1021771665"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">134</int> + <reference key="object" ref="156272785"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">136</int> + <reference key="object" ref="730606146"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">143</int> + <reference key="object" ref="594796138"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">144</int> + <reference key="object" ref="741321419"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">145</int> + <reference key="object" ref="770461341"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">149</int> + <reference key="object" ref="276734846"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">150</int> + <reference key="object" ref="644979712"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">196</int> + <reference key="object" ref="329501564"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">320</int> + <reference key="object" ref="461135404"/> + <reference key="parent" ref="499410461"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">274</int> + <reference key="object" ref="729612487"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="324022003"/> + </object> + <reference key="parent" ref="624798014"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">275</int> + <reference key="object" ref="324022003"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="463629067"/> + <reference ref="854781678"/> + <reference ref="140484273"/> + <reference ref="252305464"/> + <reference ref="495532942"/> + <reference ref="915916931"/> + <reference ref="47062370"/> + <reference ref="922159417"/> + </object> + <reference key="parent" ref="729612487"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">281</int> + <reference key="object" ref="463629067"/> + <reference key="parent" ref="324022003"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">282</int> + <reference key="object" ref="854781678"/> + <reference key="parent" ref="324022003"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">287</int> + <reference key="object" ref="140484273"/> + <reference key="parent" ref="324022003"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">289</int> + <reference key="object" ref="252305464"/> + <reference key="parent" ref="324022003"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">290</int> + <reference key="object" ref="495532942"/> + <reference key="parent" ref="324022003"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">291</int> + <reference key="object" ref="915916931"/> + <reference key="parent" ref="324022003"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">293</int> + <reference key="object" ref="47062370"/> + <reference key="parent" ref="324022003"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">301</int> + <reference key="object" ref="922159417"/> + <reference key="parent" ref="324022003"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">206</int> + <reference key="object" ref="590266459"/> + <reference key="parent" ref="0"/> + <string key="objectName">LauncherManager</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">225</int> + <reference key="object" ref="938927474"/> + <reference key="parent" ref="0"/> + <string key="objectName">IWADController</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">227</int> + <reference key="object" ref="193084417"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="145141922"/> + </object> + <reference key="parent" ref="0"/> + <string key="objectName">Configuration Window</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">228</int> + <reference key="object" ref="145141922"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="348674481"/> + <reference ref="215057262"/> + <reference ref="410786529"/> + <reference ref="316721564"/> + <reference ref="458378991"/> + <reference ref="644218899"/> + <reference ref="179636494"/> + <reference ref="1021143679"/> + <reference ref="539465960"/> + <reference ref="712311825"/> + <reference ref="355049668"/> + <reference ref="602477213"/> + <reference ref="452288864"/> + <reference ref="625273251"/> + <reference ref="680095551"/> + <reference ref="658359713"/> + </object> + <reference key="parent" ref="193084417"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">234</int> + <reference key="object" ref="348674481"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="522582983"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">235</int> + <reference key="object" ref="215057262"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="596525351"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">236</int> + <reference key="object" ref="410786529"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="673476660"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">238</int> + <reference key="object" ref="316721564"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="663066257"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">239</int> + <reference key="object" ref="458378991"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="848829815"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">240</int> + <reference key="object" ref="644218899"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="63361904"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">241</int> + <reference key="object" ref="179636494"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="84857374"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">242</int> + <reference key="object" ref="1021143679"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="629867670"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">243</int> + <reference key="object" ref="539465960"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="979277836"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">244</int> + <reference key="object" ref="712311825"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="131918744"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">245</int> + <reference key="object" ref="355049668"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="17259252"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">246</int> + <reference key="object" ref="602477213"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="406066834"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">247</int> + <reference key="object" ref="452288864"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="969661180"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">248</int> + <reference key="object" ref="625273251"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="857754300"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">249</int> + <reference key="object" ref="680095551"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="1012408786"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">250</int> + <reference key="object" ref="658359713"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="235375789"/> + </object> + <reference key="parent" ref="145141922"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">229</int> + <reference key="object" ref="805322722"/> + <reference key="parent" ref="0"/> + <string key="objectName">Doom1IWAD</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">230</int> + <reference key="object" ref="328707004"/> + <reference key="parent" ref="0"/> + <string key="objectName">Doom2IWAD</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">231</int> + <reference key="object" ref="808449249"/> + <reference key="parent" ref="0"/> + <string key="objectName">TNTIWAD</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">232</int> + <reference key="object" ref="645425571"/> + <reference key="parent" ref="0"/> + <string key="objectName">PlutoniaIWAD</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">233</int> + <reference key="object" ref="142365428"/> + <reference key="parent" ref="0"/> + <string key="objectName">ChexIWAD</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">270</int> + <reference key="object" ref="825061065"/> + <reference key="parent" ref="0"/> + <string key="objectName">AppController</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">325</int> + <reference key="object" ref="840496048"/> + <reference key="parent" ref="233433370"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">326</int> + <reference key="object" ref="968990884"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="562767686"/> + </object> + <reference key="parent" ref="936658753"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">327</int> + <reference key="object" ref="606342952"/> + <reference key="parent" ref="837745433"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">328</int> + <reference key="object" ref="339458432"/> + <reference key="parent" ref="63012253"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">329</int> + <reference key="object" ref="442641975"/> + <reference key="parent" ref="270224583"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">330</int> + <reference key="object" ref="263205275"/> + <reference key="parent" ref="165411811"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">331</int> + <reference key="object" ref="660416141"/> + <reference key="parent" ref="521193242"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">332</int> + <reference key="object" ref="139359493"/> + <reference key="parent" ref="858516582"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">333</int> + <reference key="object" ref="522582983"/> + <reference key="parent" ref="348674481"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">334</int> + <reference key="object" ref="596525351"/> + <reference key="parent" ref="215057262"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">335</int> + <reference key="object" ref="673476660"/> + <reference key="parent" ref="410786529"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">336</int> + <reference key="object" ref="663066257"/> + <reference key="parent" ref="316721564"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">337</int> + <reference key="object" ref="848829815"/> + <reference key="parent" ref="458378991"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">338</int> + <reference key="object" ref="63361904"/> + <reference key="parent" ref="644218899"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">339</int> + <reference key="object" ref="84857374"/> + <reference key="parent" ref="179636494"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">340</int> + <reference key="object" ref="629867670"/> + <reference key="parent" ref="1021143679"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">341</int> + <reference key="object" ref="979277836"/> + <reference key="parent" ref="539465960"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">342</int> + <reference key="object" ref="131918744"/> + <reference key="parent" ref="712311825"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">343</int> + <reference key="object" ref="17259252"/> + <reference key="parent" ref="355049668"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">344</int> + <reference key="object" ref="406066834"/> + <reference key="parent" ref="602477213"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">345</int> + <reference key="object" ref="969661180"/> + <reference key="parent" ref="452288864"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">346</int> + <reference key="object" ref="857754300"/> + <reference key="parent" ref="625273251"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">347</int> + <reference key="object" ref="1012408786"/> + <reference key="parent" ref="680095551"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">348</int> + <reference key="object" ref="235375789"/> + <reference key="parent" ref="658359713"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">212</int> + <reference key="object" ref="562767686"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="532676330"/> + </object> + <reference key="parent" ref="968990884"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">213</int> + <reference key="object" ref="532676330"/> + <reference key="parent" ref="562767686"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-3</int> + <reference key="object" ref="226652452"/> + <reference key="parent" ref="0"/> + <string key="objectName">Application</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">349</int> + <reference key="object" ref="201870239"/> + <reference key="parent" ref="0"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">350</int> + <reference key="object" ref="895790931"/> + <reference key="parent" ref="0"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">351</int> + <reference key="object" ref="366010945"/> + <reference key="parent" ref="0"/> + </object> + </object> + </object> + <object class="NSMutableDictionary" key="flattenedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>129.IBPluginDependency</string> + <string>129.ImportedFromIB2</string> + <string>130.IBPluginDependency</string> + <string>130.ImportedFromIB2</string> + <string>131.IBPluginDependency</string> + <string>131.ImportedFromIB2</string> + <string>134.IBPluginDependency</string> + <string>134.ImportedFromIB2</string> + <string>136.IBPluginDependency</string> + <string>136.ImportedFromIB2</string> + <string>143.IBPluginDependency</string> + <string>143.ImportedFromIB2</string> + <string>144.IBPluginDependency</string> + <string>144.ImportedFromIB2</string> + <string>145.IBPluginDependency</string> + <string>145.ImportedFromIB2</string> + <string>149.IBPluginDependency</string> + <string>149.ImportedFromIB2</string> + <string>150.IBPluginDependency</string> + <string>150.ImportedFromIB2</string> + <string>19.IBPluginDependency</string> + <string>19.ImportedFromIB2</string> + <string>196.IBPluginDependency</string> + <string>196.ImportedFromIB2</string> + <string>197.IBPluginDependency</string> + <string>197.ImportedFromIB2</string> + <string>2.IBPluginDependency</string> + <string>2.ImportedFromIB2</string> + <string>206.ImportedFromIB2</string> + <string>209.IBPluginDependency</string> + <string>209.IBViewBoundsToFrameTransform</string> + <string>209.ImportedFromIB2</string> + <string>21.IBEditorWindowLastContentRect</string> + <string>21.IBPluginDependency</string> + <string>21.IBWindowTemplateEditedContentRect</string> + <string>21.ImportedFromIB2</string> + <string>21.NSWindowTemplate.visibleAtLaunch</string> + <string>21.windowTemplate.hasMinSize</string> + <string>21.windowTemplate.minSize</string> + <string>211.IBPluginDependency</string> + <string>211.IBViewBoundsToFrameTransform</string> + <string>211.ImportedFromIB2</string> + <string>212.IBPluginDependency</string> + <string>212.ImportedFromIB2</string> + <string>213.IBPluginDependency</string> + <string>213.ImportedFromIB2</string> + <string>216.IBPluginDependency</string> + <string>216.IBViewBoundsToFrameTransform</string> + <string>216.ImportedFromIB2</string> + <string>217.IBPluginDependency</string> + <string>217.IBViewBoundsToFrameTransform</string> + <string>217.ImportedFromIB2</string> + <string>218.IBPluginDependency</string> + <string>218.IBViewBoundsToFrameTransform</string> + <string>218.ImportedFromIB2</string> + <string>219.IBPluginDependency</string> + <string>219.IBViewBoundsToFrameTransform</string> + <string>219.ImportedFromIB2</string> + <string>220.IBPluginDependency</string> + <string>220.IBViewBoundsToFrameTransform</string> + <string>220.ImportedFromIB2</string> + <string>221.IBPluginDependency</string> + <string>221.IBViewBoundsToFrameTransform</string> + <string>221.ImportedFromIB2</string> + <string>225.ImportedFromIB2</string> + <string>227.IBEditorWindowLastContentRect</string> + <string>227.IBPluginDependency</string> + <string>227.IBWindowTemplateEditedContentRect</string> + <string>227.ImportedFromIB2</string> + <string>227.windowTemplate.hasMinSize</string> + <string>227.windowTemplate.minSize</string> + <string>228.IBPluginDependency</string> + <string>228.ImportedFromIB2</string> + <string>229.ImportedFromIB2</string> + <string>23.IBPluginDependency</string> + <string>23.ImportedFromIB2</string> + <string>230.ImportedFromIB2</string> + <string>231.ImportedFromIB2</string> + <string>232.ImportedFromIB2</string> + <string>233.ImportedFromIB2</string> + <string>234.IBPluginDependency</string> + <string>234.ImportedFromIB2</string> + <string>235.IBPluginDependency</string> + <string>235.ImportedFromIB2</string> + <string>236.IBPluginDependency</string> + <string>236.ImportedFromIB2</string> + <string>238.IBPluginDependency</string> + <string>238.ImportedFromIB2</string> + <string>239.IBPluginDependency</string> + <string>239.ImportedFromIB2</string> + <string>24.IBPluginDependency</string> + <string>24.ImportedFromIB2</string> + <string>240.IBPluginDependency</string> + <string>240.ImportedFromIB2</string> + <string>241.IBPluginDependency</string> + <string>241.ImportedFromIB2</string> + <string>242.IBPluginDependency</string> + <string>242.ImportedFromIB2</string> + <string>243.IBPluginDependency</string> + <string>243.ImportedFromIB2</string> + <string>244.IBPluginDependency</string> + <string>244.ImportedFromIB2</string> + <string>245.IBPluginDependency</string> + <string>245.ImportedFromIB2</string> + <string>246.IBPluginDependency</string> + <string>246.ImportedFromIB2</string> + <string>247.IBPluginDependency</string> + <string>247.ImportedFromIB2</string> + <string>248.IBPluginDependency</string> + <string>248.ImportedFromIB2</string> + <string>249.IBPluginDependency</string> + <string>249.ImportedFromIB2</string> + <string>250.IBPluginDependency</string> + <string>250.ImportedFromIB2</string> + <string>270.ImportedFromIB2</string> + <string>274.IBPluginDependency</string> + <string>274.ImportedFromIB2</string> + <string>275.IBPluginDependency</string> + <string>275.ImportedFromIB2</string> + <string>281.IBPluginDependency</string> + <string>281.ImportedFromIB2</string> + <string>282.IBPluginDependency</string> + <string>282.ImportedFromIB2</string> + <string>287.IBPluginDependency</string> + <string>287.ImportedFromIB2</string> + <string>289.IBPluginDependency</string> + <string>289.ImportedFromIB2</string> + <string>29.IBEditorWindowLastContentRect</string> + <string>29.IBPluginDependency</string> + <string>29.ImportedFromIB2</string> + <string>290.IBPluginDependency</string> + <string>290.ImportedFromIB2</string> + <string>291.IBPluginDependency</string> + <string>291.ImportedFromIB2</string> + <string>293.IBPluginDependency</string> + <string>293.ImportedFromIB2</string> + <string>301.IBPluginDependency</string> + <string>301.ImportedFromIB2</string> + <string>320.IBPluginDependency</string> + <string>320.ImportedFromIB2</string> + <string>349.IBPluginDependency</string> + <string>350.IBPluginDependency</string> + <string>351.IBPluginDependency</string> + <string>5.IBPluginDependency</string> + <string>5.ImportedFromIB2</string> + <string>56.IBPluginDependency</string> + <string>56.ImportedFromIB2</string> + <string>57.IBPluginDependency</string> + <string>57.ImportedFromIB2</string> + <string>58.IBPluginDependency</string> + <string>58.ImportedFromIB2</string> + <string>92.IBPluginDependency</string> + <string>92.ImportedFromIB2</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <object class="NSAffineTransform"> + <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwyEAAA</bytes> + </object> + <boolean value="YES"/> + <string>{{337, 406}, {530, 190}}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>{{337, 406}, {530, 190}}</string> + <boolean value="YES"/> + <boolean value="YES"/> + <boolean value="YES"/> + <string>{243.529, 107}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <object class="NSAffineTransform"> + <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwxAAAA</bytes> + </object> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <object class="NSAffineTransform"> + <bytes key="NSTransformStruct">AUO/AABCTAAAA</bytes> + </object> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <object class="NSAffineTransform"> + <bytes key="NSTransformStruct">P4AAAL+AAABDjIAAww8AAA</bytes> + </object> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <object class="NSAffineTransform"> + <bytes key="NSTransformStruct">P4AAAL+AAABBiAAAwwoAAA</bytes> + </object> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <object class="NSAffineTransform"> + <bytes key="NSTransformStruct">P4AAAL+AAABBoAAAwu4AAA</bytes> + </object> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <object class="NSAffineTransform"> + <bytes key="NSTransformStruct">P4AAAL+AAABDwYAAwgQAAA</bytes> + </object> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <object class="NSAffineTransform"> + <bytes key="NSTransformStruct">P4AAAL+AAABBYAAAwgQAAA</bytes> + </object> + <boolean value="YES"/> + <boolean value="YES"/> + <string>{{329, 484}, {480, 316}}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>{{329, 484}, {480, 316}}</string> + <boolean value="YES"/> + <boolean value="YES"/> + <string>{213, 107}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <boolean value="YES"/> + <boolean value="YES"/> + <boolean value="YES"/> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>{{329, 814}, {223, 20}}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <boolean value="YES"/> + </object> + </object> + <object class="NSMutableDictionary" key="unlocalizedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference key="dict.sortedKeys" ref="0"/> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="activeLocalization"/> + <object class="NSMutableDictionary" key="localizations"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference key="dict.sortedKeys" ref="0"/> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="sourceID"/> + <int key="maxID">351</int> + </object> + <object class="IBClassDescriber" key="IBDocument.Classes"> + <object class="NSMutableArray" key="referencedPartialClassDescriptions"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBPartialClassDescription"> + <string key="className">AppController</string> + <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="outlets"> + <string key="NS.key.0">launcherManager</string> + <string key="NS.object.0">id</string> + </object> + <object class="NSMutableDictionary" key="toOneOutletInfosByName"> + <string key="NS.key.0">launcherManager</string> + <object class="IBToOneOutletInfo" key="NS.object.0"> + <string key="name">launcherManager</string> + <string key="candidateClassName">id</string> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBUserSource</string> + <string key="minorKey"/> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">FirstResponder</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBUserSource</string> + <string key="minorKey"/> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">IWADController</string> + <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="actions"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>closeConfigWindow:</string> + <string>openConfigWindow:</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>id</string> + <string>id</string> + </object> + </object> + <object class="NSMutableDictionary" key="actionInfosByName"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>closeConfigWindow:</string> + <string>openConfigWindow:</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBActionInfo"> + <string key="name">closeConfigWindow:</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBActionInfo"> + <string key="name">openConfigWindow:</string> + <string key="candidateClassName">id</string> + </object> + </object> + </object> + <object class="NSMutableDictionary" key="outlets"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>chex</string> + <string>configWindow</string> + <string>doom1</string> + <string>doom2</string> + <string>iwadSelector</string> + <string>plutonia</string> + <string>tnt</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>id</string> + <string>id</string> + <string>id</string> + <string>id</string> + <string>id</string> + <string>id</string> + <string>id</string> + </object> + </object> + <object class="NSMutableDictionary" key="toOneOutletInfosByName"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>chex</string> + <string>configWindow</string> + <string>doom1</string> + <string>doom2</string> + <string>iwadSelector</string> + <string>plutonia</string> + <string>tnt</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBToOneOutletInfo"> + <string key="name">chex</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">configWindow</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">doom1</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">doom2</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">iwadSelector</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">plutonia</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">tnt</string> + <string key="candidateClassName">id</string> + </object> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBUserSource</string> + <string key="minorKey"/> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">IWADLocation</string> + <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="actions"> + <string key="NS.key.0">setButtonClicked:</string> + <string key="NS.object.0">id</string> + </object> + <object class="NSMutableDictionary" key="actionInfosByName"> + <string key="NS.key.0">setButtonClicked:</string> + <object class="IBActionInfo" key="NS.object.0"> + <string key="name">setButtonClicked:</string> + <string key="candidateClassName">id</string> + </object> + </object> + <object class="NSMutableDictionary" key="outlets"> + <string key="NS.key.0">locationConfigBox</string> + <string key="NS.object.0">id</string> + </object> + <object class="NSMutableDictionary" key="toOneOutletInfosByName"> + <string key="NS.key.0">locationConfigBox</string> + <object class="IBToOneOutletInfo" key="NS.object.0"> + <string key="name">locationConfigBox</string> + <string key="candidateClassName">id</string> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBUserSource</string> + <string key="minorKey"/> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">LauncherManager</string> + <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="actions"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>launch:</string> + <string>openTerminal:</string> + <string>runSetup:</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>id</string> + <string>id</string> + <string>id</string> + </object> + </object> + <object class="NSMutableDictionary" key="actionInfosByName"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>launch:</string> + <string>openTerminal:</string> + <string>runSetup:</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBActionInfo"> + <string key="name">launch:</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBActionInfo"> + <string key="name">openTerminal:</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBActionInfo"> + <string key="name">runSetup:</string> + <string key="candidateClassName">id</string> + </object> + </object> + </object> + <object class="NSMutableDictionary" key="outlets"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>commandLineArguments</string> + <string>iwadController</string> + <string>launchButton</string> + <string>launcherWindow</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>id</string> + <string>id</string> + <string>id</string> + <string>id</string> + </object> + </object> + <object class="NSMutableDictionary" key="toOneOutletInfosByName"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>commandLineArguments</string> + <string>iwadController</string> + <string>launchButton</string> + <string>launcherWindow</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBToOneOutletInfo"> + <string key="name">commandLineArguments</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">iwadController</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">launchButton</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">launcherWindow</string> + <string key="candidateClassName">id</string> + </object> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBUserSource</string> + <string key="minorKey"/> + </object> + </object> + </object> + </object> + <int key="IBDocument.localizationMode">0</int> + <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string> + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string> + <integer value="1060" key="NS.object.0"/> + </object> + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string> + <integer value="3000" key="NS.object.0"/> + </object> + <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> + <nil key="IBDocument.LastKnownRelativeProjectPath"/> + <int key="IBDocument.defaultPropertyAccessControl">3</int> + <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>128x128</string> + <string>NSMenuCheckmark</string> + <string>NSMenuMixedState</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>{128, 128}</string> + <string>{9, 8}</string> + <string>{7, 2}</string> + </object> + </object> + </data> +</archive> diff --git a/pkg/osx/Resources/launcher.nib/info.nib b/pkg/osx/Resources/launcher.nib/info.nib deleted file mode 100644 index 512ee6dd..00000000 --- a/pkg/osx/Resources/launcher.nib/info.nib +++ /dev/null @@ -1,23 +0,0 @@ -<?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 differindex cc763056..93066265 100644 --- a/pkg/osx/Resources/launcher.nib/keyedobjects.nib +++ b/pkg/osx/Resources/launcher.nib/keyedobjects.nib diff --git a/pkg/wince/wince-cabgen b/pkg/wince/wince-cabgen index 97cba132..76845cf9 100755 --- a/pkg/wince/wince-cabgen +++ b/pkg/wince/wince-cabgen @@ -3,10 +3,11 @@ import os import re import shutil +import struct import sys import tempfile -CAB_HEADER = "MSCE" +CAB_HEADER = "MSCE".encode("ascii") ARCHITECTURES = { "shx-sh3": 103, @@ -58,16 +59,10 @@ DIR_VARIABLES = { } def write_int16(f, value): - b1 = value & 0xff - b2 = (value >> 8) & 0xff - f.write("%c%c" % (b1, b2)) + f.write(struct.pack("<H", value)) def write_int32(f, value): - b1 = value & 0xff - b2 = (value >> 8) & 0xff - b3 = (value >> 16) & 0xff - b4 = (value >> 24) & 0xff - f.write("%c%c%c%c" % (b1, b2, b3, b4)) + f.write(struct.pack("<I", value)) # Pad a string with NUL characters so that it has a length that is # a multiple of 4. At least one NUL is always added. @@ -208,7 +203,7 @@ class StringDictionary: for i, s in self.string_list: write_int16(stream, i) write_int16(stream, len(s)) - stream.write(s) + stream.write(s.encode("ascii")) class DirectoryList: def __init__(self, cab_header): @@ -252,7 +247,7 @@ class DirectoryList: # dir_path = dir_path[1:] dir_path = [ dir ] - dir_path = map(lambda x: dictionary.get(x), dir_path) + dir_path = list(map(lambda x: dictionary.get(x), dir_path)) self.directories[key] = self.index self.directories_list.append((self.index, dir_path)) @@ -334,7 +329,7 @@ class FileList: write_int16(stream, file_no) write_int32(stream, flags) write_int16(stream, len(filename)) - stream.write(filename) + stream.write(filename.encode("ascii")) # TODO? @@ -412,7 +407,7 @@ class LinkList: # Map dirs that make up the path to strings. dictionary = self.cab_header.dictionary - dest_path = map(lambda x: dictionary.get(x), dest_path) + dest_path = list(map(lambda x: dictionary.get(x), dest_path)) self.links.append((self.index, target_type, target_id, base_dir, dest_path)) @@ -492,6 +487,7 @@ class CabHeaderFile: section.write(stream) pos = stream.tell() if pos != old_pos + len(section): + print(section) raise Exception("Section is %i bytes long, but %i written" % \ (len(section), pos - old_pos)) old_pos = pos @@ -574,7 +570,7 @@ class CabFile: basename = self.__shorten_name(self.files[0], 0) filename = os.path.join(dir, basename) - stream = file(filename, "w") + stream = open(filename, "wb") self.cab_header.write(stream) stream.close() @@ -625,17 +621,17 @@ def expand_path(filename): # Expand $(xyz) path variables to their Windows equivalents: def replace_var(match): - var_name = match.group(1) + var_name = match.group(1) - if not var_name in DIR_VARIABLES: - raise Exception("Unknown variable '%s'" % var_name) - else: - return DIR_VARIABLES[var_name] + if not var_name in DIR_VARIABLES: + raise Exception("Unknown variable '%s'" % var_name) + else: + return DIR_VARIABLES[var_name] return re.sub(r"\$\((.*?)\)", replace_var, filename) def read_config_file(filename): - f = file(filename) + f = open(filename) data = f.readlines() data = "".join(data) @@ -656,10 +652,10 @@ def print_dependencies(filename): files_list = config["files"] for dest, source_file in files_list.items(): - print source_file + print(source_file) if len(sys.argv) < 3: - print "Usage: %s <config file> <output file>" % sys.argv[0] + print("Usage: %s <config file> <output file>" % sys.argv[0]) sys.exit(0) if sys.argv[1] == "-d": diff --git a/rpm.spec.in b/rpm.spec.in index b37a2876..9717ebfb 100644 --- a/rpm.spec.in +++ b/rpm.spec.in @@ -57,5 +57,6 @@ rm -rf $RPM_BUILD_ROOT %doc COPYING %doc CMDLINE %doc BUGS +%doc NOT-BUGS /usr/games/* diff --git a/src/Makefile.am b/src/Makefile.am index 2ba6dbef..0b747f89 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -34,6 +34,7 @@ net_dedicated.c net_dedicated.h \ net_io.c net_io.h \ net_packet.c net_packet.h \ net_sdl.c net_sdl.h \ +net_query.c net_query.h \ net_server.c net_server.h \ net_structrw.c net_structrw.h \ z_native.c z_zone.h @@ -142,9 +143,11 @@ EXTRA_LIBS = \ @SDLNET_LIBS@ if HAVE_WINDRES -@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc +@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc \ + $(FEATURE_MULTIPLAYER_SOURCE_FILES) else -@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) +@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) \ + $(FEATURE_MULTIPLAYER_SOURCE_FILES) endif @PROGRAM_PREFIX@doom_LDADD = doom/libdoom.a $(EXTRA_LIBS) diff --git a/src/d_iwad.c b/src/d_iwad.c index e7f25234..a6187c10 100644 --- a/src/d_iwad.c +++ b/src/d_iwad.c @@ -47,6 +47,7 @@ static iwad_t iwads[] = { "doom.wad", doom, retail, "Doom" }, { "doom1.wad", doom, shareware, "Doom Shareware" }, { "chex.wad", doom, shareware, "Chex Quest" }, + { "hacx.wad", doom2, commercial, "Hacx" }, { "heretic.wad", heretic, retail, "Heretic" }, { "heretic1.wad", heretic, shareware, "Heretic Shareware" }, { "hexen.wad", hexen, commercial, "Hexen" }, @@ -657,7 +658,7 @@ char *D_FindIWAD(int mask, GameMission_t *mission) // @arg <file> // - iwadparm = M_CheckParm("-iwad"); + iwadparm = M_CheckParmWithArgs("-iwad", 1); if (iwadparm) { diff --git a/src/d_mode.h b/src/d_mode.h index 8746b354..20cb89e2 100644 --- a/src/d_mode.h +++ b/src/d_mode.h @@ -63,6 +63,7 @@ typedef enum typedef enum { exe_doom_1_9, // Doom 1.9: used for shareware, registered and commercial + exe_hacx, // Hacx exe_ultimate, // Ultimate Doom (retail) exe_final, // Final Doom exe_chex, // Chex Quest executable (based on Final Doom) diff --git a/src/deh_io.c b/src/deh_io.c index 3386a6fa..92c81632 100644 --- a/src/deh_io.c +++ b/src/deh_io.c @@ -30,21 +30,63 @@ #include <string.h> #include "i_system.h" +#include "w_wad.h" #include "z_zone.h" #include "deh_defs.h" #include "deh_io.h" +typedef enum +{ + DEH_INPUT_FILE, + DEH_INPUT_LUMP +} deh_input_type_t; + struct deh_context_s { - FILE *stream; + deh_input_type_t type; char *filename; + + // If the input comes from a memory buffer, pointer to the memory + // buffer. + + unsigned char *input_buffer; + size_t input_buffer_len; + unsigned int input_buffer_pos; + int lumpnum; + + // If the input comes from a file, the file stream for reading + // data. + + FILE *stream; + + // Current line number that we have reached: + int linenum; + + // Used by DEH_ReadLine: + boolean last_was_newline; char *readbuffer; int readbuffer_size; }; +static deh_context_t *DEH_NewContext(void) +{ + deh_context_t *context; + + context = Z_Malloc(sizeof(*context), PU_STATIC, NULL); + + // Initial read buffer size of 128 bytes + + context->readbuffer_size = 128; + context->readbuffer = Z_Malloc(context->readbuffer_size, PU_STATIC, NULL); + context->linenum = 0; + context->last_was_newline = true; + + return context; +} + // Open a dehacked file for reading // Returns NULL if open failed @@ -52,22 +94,41 @@ 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 = DEH_NewContext(); + + context->type = DEH_INPUT_FILE; context->stream = fstream; - - // Initial read buffer size of 128 bytes + context->filename = strdup(filename); - 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; +} + +// Open a WAD lump for reading. + +deh_context_t *DEH_OpenLump(int lumpnum) +{ + deh_context_t *context; + void *lump; + + lump = W_CacheLumpNum(lumpnum, PU_STATIC); + + context = DEH_NewContext(); + + context->type = DEH_INPUT_LUMP; + context->lumpnum = lumpnum; + context->input_buffer = lump; + context->input_buffer_len = W_LumpLength(lumpnum); + context->input_buffer_pos = 0; + + context->filename = malloc(9); + strncpy(context->filename, lumpinfo[lumpnum].name, 8); + context->filename[8] = '\0'; return context; } @@ -76,33 +137,67 @@ deh_context_t *DEH_OpenFile(char *filename) void DEH_CloseFile(deh_context_t *context) { - fclose(context->stream); + if (context->type == DEH_INPUT_FILE) + { + fclose(context->stream); + } + else if (context->type == DEH_INPUT_LUMP) + { + W_ReleaseLumpNum(context->lumpnum); + } + Z_Free(context->readbuffer); Z_Free(context); } +int DEH_GetCharFile(deh_context_t *context) +{ + if (feof(context->stream)) + { + // end of file + + return -1; + } + + return fgetc(context->stream); +} + +int DEH_GetCharLump(deh_context_t *context) +{ + int result; + + if (context->input_buffer_pos >= context->input_buffer_len) + { + return -1; + } + + result = context->input_buffer[context->input_buffer_pos]; + ++context->input_buffer_pos; + + return result; +} + // 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 + do { - if (feof(context->stream)) + switch (context->type) { - // end of file + case DEH_INPUT_FILE: + result = DEH_GetCharFile(context); + break; - result = -1; + case DEH_INPUT_LUMP: + result = DEH_GetCharLump(context); + break; } - else - { - result = fgetc(context->stream); - } - } while (result == '\r'); // Track the current line number @@ -111,9 +206,9 @@ int DEH_GetChar(deh_context_t *context) { ++context->linenum; } - + context->last_was_newline = result == '\n'; - + return result; } diff --git a/src/deh_io.h b/src/deh_io.h index 061a5a0e..9d22b360 100644 --- a/src/deh_io.h +++ b/src/deh_io.h @@ -30,6 +30,7 @@ #include "deh_defs.h" deh_context_t *DEH_OpenFile(char *filename); +deh_context_t *DEH_OpenLump(int lumpnum); void DEH_CloseFile(deh_context_t *context); int DEH_GetChar(deh_context_t *context); char *DEH_ReadLine(deh_context_t *context); diff --git a/src/deh_main.c b/src/deh_main.c index 75934087..39d59e8c 100644 --- a/src/deh_main.c +++ b/src/deh_main.c @@ -32,6 +32,7 @@ #include "doomtype.h" #include "d_iwad.h" #include "m_argv.h" +#include "w_wad.h" #include "deh_defs.h" #include "deh_io.h" @@ -246,9 +247,6 @@ static void DEH_ParseContext(deh_context_t *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 (;;) @@ -260,7 +258,9 @@ static void DEH_ParseContext(deh_context_t *context) // end of file? if (line == NULL) + { return; + } while (line[0] != '\0' && isspace(line[0])) ++line; @@ -347,6 +347,48 @@ int DEH_LoadFile(char *filename) return 1; } +// Load dehacked file from WAD lump. + +int DEH_LoadLump(int lumpnum) +{ + deh_context_t *context; + + // If it's in a lump, it's probably designed for a modern source port, + // so allow it to do long string and cheat replacements. + + deh_allow_long_strings = true; + deh_allow_long_cheats = true; + + context = DEH_OpenLump(lumpnum); + + if (context == NULL) + { + fprintf(stderr, "DEH_LoadFile: Unable to open lump %i\n", lumpnum); + return 0; + } + + DEH_ParseContext(context); + + DEH_CloseFile(context); + + return 1; +} + +int DEH_LoadLumpByName(char *name) +{ + int lumpnum; + + lumpnum = W_CheckNumForName(name); + + if (lumpnum == -1) + { + fprintf(stderr, "DEH_LoadLumpByName: '%s' lump not found\n", name); + return 0; + } + + return DEH_LoadLump(lumpnum); +} + // Checks the command line for -deh argument void DEH_Init(void) @@ -387,4 +429,3 @@ void DEH_Init(void) } } - diff --git a/src/deh_main.h b/src/deh_main.h index f9cb44ca..9ac2c6c7 100644 --- a/src/deh_main.h +++ b/src/deh_main.h @@ -41,6 +41,8 @@ void DEH_Init(void); int DEH_LoadFile(char *filename); +int DEH_LoadLump(int lumpnum); +int DEH_LoadLumpByName(char *name); boolean DEH_ParseAssignment(char *line, char **variable_name, char **value); diff --git a/src/doom/d_main.c b/src/doom/d_main.c index f3a4b037..2f116f1e 100644 --- a/src/doom/d_main.c +++ b/src/doom/d_main.c @@ -122,8 +122,6 @@ int startmap; boolean autostart; int startloadgame; -FILE* debugfile; - boolean advancedemo; // Store demo, do not accept any inputs @@ -424,14 +422,6 @@ void D_DoomLoop (void) if (demorecording) G_BeginRecording (); - if (M_CheckParm ("-debugfile")) - { - char filename[20]; - sprintf (filename,"debug%i.txt",consoleplayer); - printf ("debug output to: %s\n",filename); - debugfile = fopen (filename,"w"); - } - TryRunTics(); I_SetWindowTitle(gamedescription); @@ -457,9 +447,12 @@ void D_DoomLoop (void) // process one or more tics if (singletics) { + static ticcmd_t cmds[MAXPLAYERS]; + I_StartTic (); D_ProcessEvents (); - G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]); + netcmds = cmds; + G_BuildTiccmd(&cmds[consoleplayer]); if (advancedemo) D_DoAdvanceDemo (); M_Ticker (); @@ -533,7 +526,13 @@ void D_DoAdvanceDemo (void) paused = false; gameaction = ga_nothing; - if (gamemode == retail && gameversion != exe_chex) + // The Ultimate Doom executable changed the demo sequence to add + // a DEMO4 demo. Final Doom was based on Ultimate, so also + // includes this change; however, the Final Doom IWADs do not + // include a DEMO4 lump, so the game bombs out with an error + // when it reaches this point in the demo sequence. + + if (gameversion == exe_ultimate || gameversion == exe_final) demosequence = (demosequence+1)%7; else demosequence = (demosequence+1)%6; @@ -608,8 +607,12 @@ void D_StartTitle (void) // These are from the original source: some of them are perhaps // not used in any dehacked patches -static char *banners[] = +static char *banners[] = { + // doom2.wad + " " + "DOOM 2: Hell on Earth v%i.%i" + " ", // doom1.wad " " "DOOM Shareware Startup v%i.%i" @@ -626,10 +629,6 @@ static char *banners[] = " " "The Ultimate DOOM Startup v%i.%i" " ", - // doom2.wad - " " - "DOOM 2: Hell on Earth v%i.%i" - " ", // tnt.wad " " "DOOM 2: TNT - Evilution v%i.%i" @@ -830,6 +829,18 @@ static boolean CheckChex(char *iwadname) chex_iwadname)); } +// Check if the IWAD file is the Hacx IWAD. +// Returns true if this is hacx.wad. + +static boolean CheckHacx(char *iwadname) +{ + char *hacx_iwadname = "hacx.wad"; + + return (strlen(iwadname) > strlen(hacx_iwadname) + && !strcasecmp(iwadname + strlen(iwadname) - strlen(hacx_iwadname), + hacx_iwadname)); +} + // print title for every printed line char title[128]; @@ -900,6 +911,7 @@ static struct GameVersion_t version; } gameversions[] = { {"Doom 1.9", "1.9", exe_doom_1_9}, + {"Hacx", "hacx", exe_hacx}, {"Ultimate Doom", "ultimate", exe_ultimate}, {"Final Doom", "final", exe_final}, {"Chex Quest", "chex", exe_chex}, @@ -921,9 +933,9 @@ static void InitGameVersion(void) // "ultimate" and "final". // - p = M_CheckParm("-gameversion"); + p = M_CheckParmWithArgs("-gameversion", 1); - if (p > 0) + if (p) { for (i=0; gameversions[i].description != NULL; ++i) { @@ -957,6 +969,12 @@ static void InitGameVersion(void) gameversion = exe_chex; } + else if (CheckHacx(iwadfile)) + { + // hacx exe: identified by iwad filename + + gameversion = exe_hacx; + } else if (gamemode == shareware || gamemode == registered) { // original @@ -1057,6 +1075,20 @@ static void D_Endoom(void) I_Endoom(endoom); } +static void LoadHacxDeh(void) +{ + // If this is the HACX IWAD, we need to load the DEHACKED lump. + + if (gameversion == exe_hacx) + { + if (!DEH_LoadLumpByName("DEHACKED")) + { + I_Error("DEHACKED lump not found. Please check that this is the " + "Hacx v1.2 IWAD."); + } + } +} + // // D_DoomMain // @@ -1094,6 +1126,21 @@ void D_DoomMain (void) } //! + // @category net + // + // Query the Internet master server for a global list of active + // servers. + // + + if (M_CheckParm("-search")) + { + printf("\nSearching for servers on Internet ...\n"); + p = NET_MasterQuery(NET_QueryPrintCallback, NULL); + printf("\n%i server(s) found.\n", p); + exit(0); + } + + //! // @arg <address> // @category net // @@ -1101,11 +1148,12 @@ void D_DoomMain (void) // address. // - p = M_CheckParm("-query"); + p = M_CheckParmWithArgs("-query", 1); - if (p > 0) + if (p) { NET_QueryAddress(myargv[p+1]); + exit(0); } //! @@ -1114,8 +1162,13 @@ void D_DoomMain (void) // Search the local LAN for running servers. // - if (M_CheckParm("-search")) - NET_LANQuery(); + if (M_CheckParm("-localsearch")) + { + printf("\nSearching for servers on local LAN ...\n"); + p = NET_LANQuery(NET_QueryPrintCallback, NULL); + printf("\n%i server(s) found.\n", p); + exit(0); + } #endif @@ -1265,40 +1318,32 @@ void D_DoomMain (void) D_AddFile(iwadfile); modifiedgame = W_ParseCommandLine(); - // add any files specified on the command line with -file wadfile - // to the wad list + //! + // @arg <files> + // @vanilla // - // convenience hack to allow -wart e m to add a wad file - // prepend a tilde to the filename so wadfile will be reloadable - p = M_CheckParm ("-wart"); + // Load the specified PWAD files. + // + + p = M_CheckParmWithArgs("-file", 1); if (p) { - myargv[p][4] = 'p'; // big hack, change to -warp + // the parms after p are wadfile/lump names, + // until end of parms or another - preceded parm + modifiedgame = true; // homebrew levels + while (++p != myargc && myargv[p][0] != '-') + { + char *filename; - // Map name handling. - switch (gamemode ) - { - case shareware: - case retail: - case registered: - sprintf (file,"~"DEVMAPS"E%cM%c.wad", - myargv[p+1][0], myargv[p+2][0]); - printf("Warping to Episode %s, Map %s.\n", - myargv[p+1],myargv[p+2]); - break; - - case commercial: - default: - p = atoi (myargv[p+1]); - if (p<10) - sprintf (file,"~"DEVMAPS"cdata/map0%i.wad", p); - else - sprintf (file,"~"DEVMAPS"cdata/map%i.wad", p); - break; - } - D_AddFile (file); + filename = D_TryFindWADByName(myargv[p]); + + D_AddFile(filename); + } } + // Debug: +// W_PrintDirectory(); + //! // @arg <demo> // @category demo @@ -1307,7 +1352,7 @@ void D_DoomMain (void) // Play back the demo named demo.lmp. // - p = M_CheckParm ("-playdemo"); + p = M_CheckParmWithArgs ("-playdemo", 1); if (!p) { @@ -1319,11 +1364,11 @@ void D_DoomMain (void) // Play back the demo named demo.lmp, determining the framerate // of the screen. // - p = M_CheckParm ("-timedemo"); + p = M_CheckParmWithArgs("-timedemo", 1); } - if (p && p < myargc-1) + if (p) { if (!strcasecmp(myargv[p+1] + strlen(myargv[p+1]) - 4, ".lmp")) { @@ -1362,6 +1407,7 @@ void D_DoomMain (void) D_IdentifyVersion(); InitGameVersion(); LoadChexDeh(); + LoadHacxDeh(); D_SetGameDescription(); SetSaveGameDir(iwadfile); @@ -1404,9 +1450,9 @@ void D_DoomMain (void) // 0 disables all monsters. // - p = M_CheckParm ("-skill"); + p = M_CheckParmWithArgs("-skill", 1); - if (p && p < myargc-1) + if (p) { startskill = myargv[p+1][0]-'1'; autostart = true; @@ -1419,9 +1465,9 @@ void D_DoomMain (void) // Start playing on episode n (1-4) // - p = M_CheckParm ("-episode"); + p = M_CheckParmWithArgs("-episode", 1); - if (p && p < myargc-1) + if (p) { startepisode = myargv[p+1][0]-'0'; startmap = 1; @@ -1438,12 +1484,11 @@ void D_DoomMain (void) // For multiplayer games: exit each level after n minutes. // - p = M_CheckParm ("-timer"); + p = M_CheckParmWithArgs("-timer", 1); - if (p && p < myargc-1 && deathmatch) + if (p) { timelimit = atoi(myargv[p+1]); - printf("timer: %i\n", timelimit); } //! @@ -1455,10 +1500,8 @@ void D_DoomMain (void) p = M_CheckParm ("-avg"); - if (p && p < myargc-1 && deathmatch) + if (p) { - DEH_printf("Austin Virtual Gaming: Levels will end " - "after 20 minutes\n"); timelimit = 20; } @@ -1470,9 +1513,9 @@ void D_DoomMain (void) // (Doom 2) // - p = M_CheckParm ("-warp"); + p = M_CheckParmWithArgs("-warp", 1); - if (p && p < myargc-1) + if (p) { if (gamemode == commercial) startmap = atoi (myargv[p+1]); @@ -1516,9 +1559,9 @@ void D_DoomMain (void) // Load the game in slot s. // - p = M_CheckParm ("-loadgame"); + p = M_CheckParmWithArgs("-loadgame", 1); - if (p && p < myargc-1) + if (p) { startloadgame = atoi(myargv[p+1]); } @@ -1588,24 +1631,24 @@ void D_DoomMain (void) // Record a demo named x.lmp. // - p = M_CheckParm ("-record"); + p = M_CheckParmWithArgs("-record", 1); - if (p && p < myargc-1) + if (p) { G_RecordDemo (myargv[p+1]); autostart = true; } - p = M_CheckParm ("-playdemo"); - if (p && p < myargc-1) + p = M_CheckParmWithArgs("-playdemo", 1); + if (p) { singledemo = true; // quit after one demo G_DeferedPlayDemo (demolumpname); D_DoomLoop (); // never returns } - p = M_CheckParm ("-timedemo"); - if (p && p < myargc-1) + p = M_CheckParmWithArgs("-timedemo", 1); + if (p) { G_TimeDemo (demolumpname); D_DoomLoop (); // never returns diff --git a/src/doom/d_net.c b/src/doom/d_net.c index 464922d4..dd1ec563 100644 --- a/src/doom/d_net.c +++ b/src/doom/d_net.c @@ -25,7 +25,7 @@ // //----------------------------------------------------------------------------- - +#include <stdlib.h> #include "doomfeatures.h" @@ -49,26 +49,34 @@ #include "net_sdl.h" #include "net_loop.h" +// The complete set of data for a particular tic. + +typedef struct +{ + ticcmd_t cmds[MAXPLAYERS]; + boolean ingame[MAXPLAYERS]; +} ticcmd_set_t; // // NETWORKING // // gametic is the tic about to (or currently being) run -// maketic is the tick that hasn't had control made for it yet -// nettics[] has the maketics for all players +// maketic is the tic that hasn't had control made for it yet +// recvtic is the latest tic received from the server. // -// a gametic cannot be run until nettics[] > gametic for all players +// a gametic cannot be run until ticcmds are received for it +// from all players. // -ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; -int nettics[MAXPLAYERS]; +ticcmd_set_t ticdata[BACKUPTICS]; +ticcmd_t *netcmds; int maketic; +int recvtic; // Used for original sync code. -int lastnettic; -int skiptics = 0; +static int skiptics = 0; // Reduce the bandwidth needed by sampling game input less and transmitting // less. If ticdup is 2, sample half normal, 3 = one third normal, etc. @@ -85,11 +93,7 @@ fixed_t offsetms; // Use new client syncronisation code -boolean net_cl_new_sync = true; - -// Connected but not participating in the game (observer) - -boolean drone = false; +boolean new_sync = true; // 35 fps clock adjusted by offsetms milliseconds @@ -99,7 +103,7 @@ static int GetAdjustedTime(void) time_ms = I_GetTimeMS(); - if (net_cl_new_sync) + if (new_sync) { // Use the adjustments from net_client.c only if we are // using the new sync mode. @@ -177,7 +181,7 @@ void NetUpdate (void) continue; } - if (net_cl_new_sync) + if (new_sync) { // If playing single player, do not allow tics to buffer // up very far @@ -200,20 +204,95 @@ void NetUpdate (void) G_BuildTiccmd(&cmd); #ifdef FEATURE_MULTIPLAYER - - if (netgame && !demoplayback) + + if (net_client_connected) { NET_CL_SendTiccmd(&cmd, maketic); } #endif - netcmds[consoleplayer][maketic % BACKUPTICS] = cmd; + ticdata[maketic % BACKUPTICS].cmds[consoleplayer] = cmd; + ticdata[maketic % BACKUPTICS].ingame[consoleplayer] = true; ++maketic; - nettics[consoleplayer] = maketic; } } +// Called when a player leaves the game + +static void D_PlayerQuitGame(player_t *player) +{ + static char exitmsg[80]; + unsigned int player_num; + + player_num = player - players; + + // Do this the same way as Vanilla Doom does, to allow dehacked + // replacements of this message + + strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg)); + exitmsg[sizeof(exitmsg) - 1] = '\0'; + + exitmsg[7] += player_num; + + playeringame[player_num] = false; + players[consoleplayer].message = exitmsg; + + // TODO: check if it is sensible to do this: + + if (demorecording) + { + G_CheckDemoStatus (); + } +} + +static void D_Disconnected(void) +{ + // In drone mode, the game cannot continue once disconnected. + + if (drone) + { + I_Error("Disconnected from server in drone mode."); + } + + // disconnected from server + + printf("Disconnected from server.\n"); +} + +// +// Invoked by the network engine when a complete set of ticcmds is +// available. +// + +void D_ReceiveTic(ticcmd_t *ticcmds, boolean *players_mask) +{ + int i; + + // Disconnected from server? + + if (ticcmds == NULL && players_mask == NULL) + { + D_Disconnected(); + return; + } + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (!drone && i == consoleplayer) + { + // This is us. Don't overwrite it. + } + else + { + ticdata[recvtic % BACKUPTICS].cmds[i] = ticcmds[i]; + ticdata[recvtic % BACKUPTICS].ingame[i] = players_mask[i]; + } + } + + ++recvtic; +} + // // Start game loop // @@ -225,169 +304,340 @@ void D_StartGameLoop(void) lasttime = GetAdjustedTime() / ticdup; } +// Load game settings from the specified structure and +// set global variables. -// -// D_CheckNetGame -// Works out player numbers among the net participants -// -extern int viewangleoffset; +static void LoadGameSettings(net_gamesettings_t *settings) +{ + unsigned int i; + + deathmatch = settings->deathmatch; + ticdup = settings->ticdup; + extratics = settings->extratics; + startepisode = settings->episode; + startmap = settings->map; + startskill = settings->skill; + startloadgame = settings->loadgame; + lowres_turn = settings->lowres_turn; + nomonsters = settings->nomonsters; + fastparm = settings->fast_monsters; + respawnparm = settings->respawn_monsters; + timelimit = settings->timelimit; + + if (lowres_turn) + { + printf("NOTE: Turning resolution is reduced; this is probably " + "because there is a client recording a Vanilla demo.\n"); + } -void D_CheckNetGame (void) + new_sync = settings->new_sync; + + if (new_sync == false) + { + printf("Syncing netgames like Vanilla Doom.\n"); + } + + if (!drone) + { + consoleplayer = settings->consoleplayer; + } + else + { + consoleplayer = 0; + } + + for (i=0; i<MAXPLAYERS; ++i) + { + playeringame[i] = i < settings->num_players; + } +} + +// Save the game settings from global variables to the specified +// game settings structure. + +static void SaveGameSettings(net_gamesettings_t *settings, + net_connect_data_t *connect_data) { int i; - int num_players; - // Call D_QuitNetGame on exit + // Fill in game settings structure with appropriate parameters + // for the new game + + settings->deathmatch = deathmatch; + settings->episode = startepisode; + settings->map = startmap; + settings->skill = startskill; + settings->loadgame = startloadgame; + settings->gameversion = gameversion; + settings->nomonsters = nomonsters; + settings->fast_monsters = fastparm; + settings->respawn_monsters = respawnparm; + settings->timelimit = timelimit; + + settings->lowres_turn = M_CheckParm("-record") > 0 + && M_CheckParm("-longtics") == 0; + + //! + // @category net + // + // Use original game sync code. + // + + if (M_CheckParm("-oldsync") > 0) + settings->new_sync = 0; + else + settings->new_sync = 1; + + //! + // @category net + // @arg <n> + // + // Send n extra tics in every packet as insurance against dropped + // packets. + // + + i = M_CheckParmWithArgs("-extratics", 1); + + if (i > 0) + settings->extratics = atoi(myargv[i+1]); + else + settings->extratics = 1; - I_AtExit(D_QuitNetGame, true); + //! + // @category net + // @arg <n> + // + // Reduce the resolution of the game by a factor of n, reducing + // the amount of network bandwidth needed. + // + + i = M_CheckParmWithArgs("-dup", 1); + + if (i > 0) + settings->ticdup = atoi(myargv[i+1]); + else + settings->ticdup = 1; + + // + // Connect data + // + + // Game type fields: + + connect_data->gamemode = gamemode; + connect_data->gamemission = gamemission; + // Drone mode? + + connect_data->drone = M_CheckParm("-drone") > 0; + + // Are we recording a demo? Possibly set lowres turn mode + + connect_data->lowres_turn = settings->lowres_turn; +} + +void D_InitSinglePlayerGame(net_gamesettings_t *settings) +{ // default values for single player - consoleplayer = 0; + settings->consoleplayer = 0; + settings->num_players = 1; + netgame = false; - ticdup = 1; - extratics = 1; - lowres_turn = false; - offsetms = 0; - - for (i=0; i<MAXPLAYERS; i++) + + //! + // @category net + // + // Start the game playing as though in a netgame with a single + // player. This can also be used to play back single player netgame + // demos. + // + + if (M_CheckParm("-solo-net") > 0) { - playeringame[i] = false; - nettics[i] = 0; + netgame = true; } +} + +boolean D_InitNetGame(net_connect_data_t *connect_data, + net_gamesettings_t *settings) +{ + net_addr_t *addr = NULL; + int i; - playeringame[0] = true; #ifdef FEATURE_MULTIPLAYER + //! + // @category net + // + // Start a multiplayer server, listening for connections. + // + + if (M_CheckParm("-server") > 0) { - net_addr_t *addr = NULL; + NET_SV_Init(); + NET_SV_AddModule(&net_loop_server_module); + NET_SV_AddModule(&net_sdl_module); + NET_SV_RegisterWithMaster(); - //! + net_loop_client_module.InitClient(); + addr = net_loop_client_module.ResolveAddress(NULL); + } + else + { + //! // @category net // - // Start a multiplayer server, listening for connections. + // Automatically search the local LAN for a multiplayer + // server and join it. // - if (M_CheckParm("-server") > 0) + i = M_CheckParm("-autojoin"); + + if (i > 0) { - NET_SV_Init(); - NET_SV_AddModule(&net_loop_server_module); - NET_SV_AddModule(&net_sdl_module); + addr = NET_FindLANServer(); - net_loop_client_module.InitClient(); - addr = net_loop_client_module.ResolveAddress(NULL); + if (addr == NULL) + { + I_Error("No server found on local LAN"); + } } - else - { - //! - // @category net - // - // Automatically search the local LAN for a multiplayer - // server and join it. - // - i = M_CheckParm("-autojoin"); + //! + // @arg <address> + // @category net + // + // Connect to a multiplayer server running on the given + // address. + // + + i = M_CheckParmWithArgs("-connect", 1); - if (i > 0) - { - addr = NET_FindLANServer(); + if (i > 0) + { + net_sdl_module.InitClient(); + addr = net_sdl_module.ResolveAddress(myargv[i+1]); - if (addr == NULL) - { - I_Error("No server found on local LAN"); - } + if (addr == NULL) + { + I_Error("Unable to resolve '%s'\n", myargv[i+1]); } + } + } - //! - // @arg <address> - // @category net - // - // Connect to a multiplayer server running on the given - // address. - // - - i = M_CheckParm("-connect"); - - if (i > 0) - { - net_sdl_module.InitClient(); - addr = net_sdl_module.ResolveAddress(myargv[i+1]); + if (addr != NULL) + { + if (M_CheckParm("-drone") > 0) + { + connect_data->drone = true; + } - if (addr == NULL) - { - I_Error("Unable to resolve '%s'\n", myargv[i+1]); - } - } + //! + // @category net + // + // Run as the left screen in three screen mode. + // + + if (M_CheckParm("-left") > 0) + { + viewangleoffset = ANG90; + connect_data->drone = true; } - if (addr != NULL) + //! + // @category net + // + // Run as the right screen in three screen mode. + // + + if (M_CheckParm("-right") > 0) { - if (M_CheckParm("-drone") > 0) - { - drone = true; - } + viewangleoffset = ANG270; + connect_data->drone = true; + } - //! - // @category net - // - // Run as the left screen in three screen mode. - // + if (!NET_CL_Connect(addr, connect_data)) + { + I_Error("D_CheckNetGame: Failed to connect to %s\n", + NET_AddrToString(addr)); + } - if (M_CheckParm("-left") > 0) - { - viewangleoffset = ANG90; - drone = true; - } + printf("D_CheckNetGame: Connected to %s\n", NET_AddrToString(addr)); - //! - // @category net - // - // Run as the right screen in three screen mode. - // + // Wait for game start message received from server. - if (M_CheckParm("-right") > 0) - { - viewangleoffset = ANG270; - drone = true; - } + NET_WaitForStart(settings); - if (!NET_CL_Connect(addr)) - { - I_Error("D_CheckNetGame: Failed to connect to %s\n", - NET_AddrToString(addr)); - } + // Read the game settings that were received. - printf("D_CheckNetGame: Connected to %s\n", NET_AddrToString(addr)); + NET_CL_GetSettings(settings); - NET_WaitForStart(); - } + return true; } #endif - num_players = 0; + return false; +} + +// +// D_CheckNetGame +// Works out player numbers among the net participants +// +extern int viewangleoffset; + +void D_CheckNetGame (void) +{ + net_connect_data_t connect_data; + net_gamesettings_t settings; - for (i=0; i<MAXPLAYERS; ++i) + offsetms = 0; + recvtic = 0; + + // Call D_QuitNetGame on exit + + I_AtExit(D_QuitNetGame, true); + + SaveGameSettings(&settings, &connect_data); + + if (D_InitNetGame(&connect_data, &settings)) { - if (playeringame[i]) - ++num_players; + netgame = true; + autostart = true; } + else + { + D_InitSinglePlayerGame(&settings); + } + + LoadGameSettings(&settings); DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode); DEH_printf("player %i of %i (%i nodes)\n", - consoleplayer+1, num_players, num_players); + consoleplayer+1, settings.num_players, settings.num_players); // Show players here; the server might have specified a time limit - if (timelimit > 0) + if (timelimit > 0 && deathmatch) { - DEH_printf("Levels will end after %d minute", timelimit); - if (timelimit > 1) - printf("s"); - printf(".\n"); + // Gross hack to work like Vanilla: + + if (timelimit == 20 && M_CheckParm("-avg")) + { + DEH_printf("Austin Virtual Gaming: Levels will end " + "after 20 minutes\n"); + } + else + { + DEH_printf("Levels will end after %d minute", timelimit); + if (timelimit > 1) + printf("s"); + printf(".\n"); + } } } @@ -399,9 +649,6 @@ void D_CheckNetGame (void) // void D_QuitNetGame (void) { - if (debugfile) - fclose (debugfile); - #ifdef FEATURE_MULTIPLAYER NET_SV_Shutdown(); @@ -411,62 +658,172 @@ void D_QuitNetGame (void) } -// Returns true if there are currently any players in the game. +static int GetLowTic(void) +{ + int lowtic; -static boolean PlayersInGame(void) + lowtic = maketic; + +#ifdef FEATURE_MULTIPLAYER + if (net_client_connected) + { + if (drone || recvtic < lowtic) + { + lowtic = recvtic; + } + } +#endif + + return lowtic; +} + +int frametics[4]; +int frameon; +int frameskip[4]; +int oldnettics; + +static void OldNetSync(void) { - int i; + unsigned int i; + unsigned int keyplayer = -1; - for (i=0; i<MAXPLAYERS; ++i) + frameon++; + + // ideally maketic should be 1 - 3 tics above lowtic + // if we are consistantly slower, speed up time + + for (i=0 ; i<MAXPLAYERS ; i++) { + // TODO: playeringame should not be used here. + if (playeringame[i]) { - return true; + keyplayer = i; + break; } } - return false; + if (keyplayer < 0) + { + // If there are no players, we can never advance anyway + + return; + } + + if (consoleplayer == keyplayer) + { + // the key player does not adapt + } + else + { + if (maketic <= recvtic) + { + lasttime--; + // printf ("-"); + } + + frameskip[frameon & 3] = oldnettics > recvtic; + oldnettics = maketic; + + if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3]) + { + skiptics = 1; + // printf ("+"); + } + } } -static int GetLowTic(void) +// Returns true if there are players in the game: + +static boolean PlayersInGame(void) { - int lowtic; + boolean result = false; + unsigned int i; + + // If we are connected to a server, check if there are any players + // in the game. -#ifdef FEATURE_MULTIPLAYER if (net_client_connected) { - int i; - - lowtic = INT_MAX; - - for (i=0; i<MAXPLAYERS; ++i) + for (i = 0; i < MAXPLAYERS; ++i) { - if (playeringame[i]) - { - if (nettics[i] < lowtic) - lowtic = nettics[i]; - } + result = result || playeringame[i]; } } - else -#endif + + // Whether single or multi-player, unless we are running as a drone, + // we are in the game. + + if (!drone) { - lowtic = maketic; + result = true; } - return lowtic; + return result; +} + +// When using ticdup, certain values must be cleared out when running +// the duplicate ticcmds. + +static void TicdupSquash(ticcmd_set_t *set) +{ + ticcmd_t *cmd; + unsigned int i; + + for (i = 0; i < MAXPLAYERS ; ++i) + { + cmd = &set->cmds[i]; + cmd->chatchar = 0; + if (cmd->buttons & BT_SPECIAL) + cmd->buttons = 0; + } +} + +static void D_RunTic(ticcmd_set_t *set) +{ + extern boolean advancedemo; + unsigned int i; + + // Check for player quits. + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && !set->ingame[i]) + { + D_PlayerQuitGame(&players[i]); + } + } + + netcmds = set->cmds; + + // check that there are players in the game. if not, we cannot + // run a tic. + + if (advancedemo) + D_DoAdvanceDemo (); + + G_Ticker (); +} + +// When running in single player mode, clear all the ingame[] array +// except the consoleplayer. + +static void SinglePlayerClear(ticcmd_set_t *set) +{ + unsigned int i; + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (i != consoleplayer) + { + set->ingame[i] = false; + } + } } // // TryRunTics // -int oldnettics; -int frametics[4]; -int frameon; -int frameskip[4]; -int oldnettics; - -extern boolean advancedemo; void TryRunTics (void) { @@ -492,7 +849,7 @@ void TryRunTics (void) // decide how many tics to run - if (net_cl_new_sync) + if (new_sync) { counts = availabletics; } @@ -509,52 +866,9 @@ void TryRunTics (void) if (counts < 1) counts = 1; - frameon++; - - if (!demoplayback) + if (net_client_connected) { - int keyplayer = -1; - - // ideally maketic should be 1 - 3 tics above lowtic - // if we are consistantly slower, speed up time - - for (i=0 ; i<MAXPLAYERS ; i++) - { - if (playeringame[i]) - { - keyplayer = i; - break; - } - } - - if (keyplayer < 0) - { - // If there are no players, we can never advance anyway - - return; - } - - if (consoleplayer == keyplayer) - { - // the key player does not adapt - } - else - { - if (maketic <= nettics[keyplayer]) - { - lasttime--; - // printf ("-"); - } - - frameskip[frameon & 3] = (oldnettics > nettics[keyplayer]); - oldnettics = maketic; - - if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3]) - { - skiptics = 1; - // printf ("+"); - } - } + OldNetSync(); } } @@ -586,41 +900,33 @@ void TryRunTics (void) // run the count * ticdup dics while (counts--) { + ticcmd_set_t *set; + + if (!PlayersInGame()) + { + return; + } + + set = &ticdata[(gametic / ticdup) % BACKUPTICS]; + + if (!net_client_connected) + { + SinglePlayerClear(set); + } + for (i=0 ; i<ticdup ; i++) { - // check that there are players in the game. if not, we cannot - // run a tic. - - if (!PlayersInGame()) - { - return; - } - - if (gametic/ticdup > lowtic) - I_Error ("gametic>lowtic"); - if (advancedemo) - D_DoAdvanceDemo (); + if (gametic/ticdup > lowtic) + I_Error ("gametic>lowtic"); - G_Ticker (); + D_RunTic(set); gametic++; // modify command for duplicated tics - if (i != ticdup-1) - { - ticcmd_t *cmd; - int buf; - int j; - - buf = (gametic/ticdup)%BACKUPTICS; - for (j=0 ; j<MAXPLAYERS ; j++) - { - cmd = &netcmds[j][buf]; - cmd->chatchar = 0; - if (cmd->buttons & BT_SPECIAL) - cmd->buttons = 0; - } - } + + TicdupSquash(set); } + NetUpdate (); // check for new console commands } } diff --git a/src/doom/d_net.h b/src/doom/d_net.h index f801d216..a3c1a43c 100644 --- a/src/doom/d_net.h +++ b/src/doom/d_net.h @@ -45,7 +45,6 @@ void TryRunTics (void); // Called at start of game loop to initialize timers void D_StartGameLoop(void); -extern boolean drone; extern boolean net_cl_new_sync; #endif diff --git a/src/doom/doomstat.h b/src/doom/doomstat.h index 40147833..237234d8 100644 --- a/src/doom/doomstat.h +++ b/src/doom/doomstat.h @@ -255,7 +255,6 @@ extern int maxammo[NUMAMMO]; // File handling stuff. extern char * savegamedir; extern char basedefault[1024]; -extern FILE* debugfile; // if true, load all graphics at level load extern boolean precache; @@ -289,7 +288,7 @@ extern int rndindex; extern int maketic; extern int nettics[MAXPLAYERS]; -extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; +extern ticcmd_t *netcmds; extern int ticdup; diff --git a/src/doom/dstrings.h b/src/doom/dstrings.h index bdc6b2ce..d47fc1af 100644 --- a/src/doom/dstrings.h +++ b/src/doom/dstrings.h @@ -38,15 +38,6 @@ #define SAVEGAMENAME "doomsav" -// -// File locations, -// relative to current position. -// Path names are OS-sensitive. -// -#define DEVMAPS "devmaps" -#define DEVDATA "devdata" - - // QuitDOOM messages // 8 per each game type #define NUM_QUITMESSAGES 8 diff --git a/src/doom/g_game.c b/src/doom/g_game.c index ad7155a0..5662d3f2 100644 --- a/src/doom/g_game.c +++ b/src/doom/g_game.c @@ -138,7 +138,7 @@ int gametic; int levelstarttic; // gametic at level start int totalkills, totalitems, totalsecret; // for intermission -char demoname[32]; +char *demoname; boolean demorecording; boolean longtics; // cph's doom 1.91 longtics hack boolean lowres_turn; // low resolution turning for longtics @@ -986,9 +986,9 @@ void G_Ticker (void) if (playeringame[i]) { cmd = &players[i].cmd; - - memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t)); - + + memcpy(cmd, &netcmds[i], sizeof(ticcmd_t)); + if (demoplayback) G_ReadDemoTiccmd (cmd); if (demorecording) @@ -1978,14 +1978,14 @@ void G_WriteDemoTiccmd (ticcmd_t* cmd) // // G_RecordDemo // -void G_RecordDemo (char* name) +void G_RecordDemo (char *name) { int i; int maxsize; usergame = false; - strcpy (demoname, name); - strcat (demoname, ".lmp"); + demoname = Z_Malloc(strlen(name) + 5, PU_STATIC, NULL); + sprintf(demoname, "%s.lmp", name); maxsize = 0x20000; //! @@ -1996,8 +1996,8 @@ void G_RecordDemo (char* name) // Specify the demo buffer size (KiB) // - i = M_CheckParm ("-maxdemo"); - if (i && i<myargc-1) + i = M_CheckParmWithArgs("-maxdemo", 1); + if (i) maxsize = atoi(myargv[i+1])*1024; demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL); demoend = demobuffer + maxsize; @@ -2145,16 +2145,11 @@ void G_DoPlayDemo (void) for (i=0 ; i<MAXPLAYERS ; i++) playeringame[i] = *demo_p++; - //! - // @category demo - // - // Play back a demo recorded in a netgame with a single player. - // - - if (playeringame[1] || M_CheckParm("-netdemo") > 0) - { - netgame = true; - netdemo = true; + if (playeringame[1] || M_CheckParm("-solo-net") > 0 + || M_CheckParm("-netdemo") > 0) + { + netgame = true; + netdemo = true; } // don't spend a lot of time in loadlevel diff --git a/src/doom/m_menu.c b/src/doom/m_menu.c index a6f7bbfb..478e7f66 100644 --- a/src/doom/m_menu.c +++ b/src/doom/m_menu.c @@ -762,6 +762,8 @@ void M_DrawReadThis1(void) switch (gameversion) { case exe_doom_1_9: + case exe_hacx: + if (gamemode == commercial) { // Doom 2 @@ -1440,23 +1442,23 @@ boolean M_Responder (event_t* ev) if (ev->type == ev_joystick && joywait < I_GetTime()) { - if (ev->data3 == -1) + if (ev->data3 < 0) { key = key_menu_up; joywait = I_GetTime() + 5; } - else if (ev->data3 == 1) + else if (ev->data3 > 0) { key = key_menu_down; joywait = I_GetTime() + 5; } - if (ev->data2 == -1) + if (ev->data2 < 0) { key = key_menu_left; joywait = I_GetTime() + 2; } - else if (ev->data2 == 1) + else if (ev->data2 > 0) { key = key_menu_right; joywait = I_GetTime() + 2; diff --git a/src/doom/p_map.c b/src/doom/p_map.c index 925e4398..78102bdf 100644 --- a/src/doom/p_map.c +++ b/src/doom/p_map.c @@ -1426,7 +1426,7 @@ static void SpechitOverrun(line_t *ld) // Use the specified magic value when emulating spechit overruns. // - p = M_CheckParm("-spechit"); + p = M_CheckParmWithArgs("-spechit", 1); if (p > 0) { diff --git a/src/doom/p_setup.c b/src/doom/p_setup.c index 7d9d4318..3fc95cab 100644 --- a/src/doom/p_setup.c +++ b/src/doom/p_setup.c @@ -755,17 +755,7 @@ P_SetupLevel // Make sure all sounds are stopped before Z_FreeTags. S_Start (); - -#if 0 // UNUSED - if (debugfile) - { - Z_FreeTags (PU_LEVEL, INT_MAX); - Z_FileDumpHeap (debugfile); - } - else -#endif - Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1); - + Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1); // UNUSED W_Profile (); P_InitThinkers (); diff --git a/src/doom/p_spec.c b/src/doom/p_spec.c index 37beb850..90d0bb7c 100644 --- a/src/doom/p_spec.c +++ b/src/doom/p_spec.c @@ -1213,9 +1213,9 @@ static void DonutOverrun(fixed_t *s3_floorheight, short *s3_floorpic, // system. The default (if this option is not specified) is to // emulate the behavior when running under Windows 98. - p = M_CheckParm("-donut"); + p = M_CheckParmWithArgs("-donut", 2); - if (p > 0 && p < myargc - 2) + if (p > 0) { // Dump of needed memory: (fixed_t)0000:0000 and (short)0000:0008 // @@ -1389,10 +1389,9 @@ void P_SpawnSpecials (void) if (W_CheckNumForName(DEH_String("texture2")) >= 0) episode = 2; - // See if -TIMER was specified. - if (timelimit > 0) + if (timelimit > 0 && deathmatch) { levelTimer = true; levelTimeCount = timelimit * 60 * TICRATE; @@ -1401,7 +1400,7 @@ void P_SpawnSpecials (void) { levelTimer = false; } - + // Init special SECTORs. sector = sectors; for (i=0 ; i<numsectors ; i++, sector++) diff --git a/src/doom/r_data.c b/src/doom/r_data.c index b999e916..505f1ff7 100644 --- a/src/doom/r_data.c +++ b/src/doom/r_data.c @@ -413,6 +413,7 @@ R_GetColumn static void GenerateTextureHashTable(void) { + texture_t **rover; int i; int key; @@ -429,12 +430,25 @@ static void GenerateTextureHashTable(void) textures[i]->index = i; - // Hook into hash table + // Vanilla Doom does a linear search of the texures array + // and stops at the first entry it finds. If there are two + // entries with the same name, the first one in the array + // wins. The new entry must therefore be added at the end + // of the hash chain, so that earlier entries win. key = W_LumpNameHash(textures[i]->name) % numtextures; - textures[i]->next = textures_hashtable[key]; - textures_hashtable[key] = textures[i]; + rover = &textures_hashtable[key]; + + while (*rover != NULL) + { + rover = &(*rover)->next; + } + + // Hook into hash table + + textures[i]->next = NULL; + *rover = textures[i]; } } diff --git a/src/doomfeatures.h b/src/doomfeatures.h index c5e6067a..1c994b70 100644 --- a/src/doomfeatures.h +++ b/src/doomfeatures.h @@ -36,8 +36,9 @@ #define FEATURE_DEHACKED 1 // Enables multiplayer support (network games) +// STRIFE-TODO: multiplayer is currently broken ... -//#define FEATURE_MULTIPLAYER 1 +// #define FEATURE_MULTIPLAYER 1 // Enables sound output diff --git a/src/i_sdlsound.c b/src/i_sdlsound.c index 7deb683d..1cfafa6f 100644 --- a/src/i_sdlsound.c +++ b/src/i_sdlsound.c @@ -53,6 +53,8 @@ #define MAX_SOUND_SLICE_TIME 70 /* ms */ #define NUM_CHANNELS 16 +static boolean setpanning_workaround = false; + static boolean sound_initialized = false; static sfxinfo_t *channels_playing[NUM_CHANNELS]; @@ -632,10 +634,19 @@ static void I_SDL_UpdateSoundParams(int handle, int vol, int sep) if (right < 0) right = 0; else if (right > 255) right = 255; + // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning + // function. A workaround is to call Mix_UnregisterAllEffects for + // the channel before calling it. This is undesirable as it may lead + // to the channel volumes resetting briefly. + + if (setpanning_workaround) + { + Mix_UnregisterAllEffects(handle); + } + Mix_SetPanning(handle, left, right); } - // // Starting a sound means adding it // to the current list of active sounds @@ -822,8 +833,34 @@ static boolean I_SDL_InitSound(boolean _use_sfx_prefix) } #endif + // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning + // function that can cause the game to lock up. If we're using an old + // version, we need to apply a workaround. But the workaround has its + // own drawbacks ... + + { + const SDL_version *mixer_version; + int v; + + mixer_version = Mix_Linked_Version(); + v = SDL_VERSIONNUM(mixer_version->major, + mixer_version->minor, + mixer_version->patch); + + if (v <= SDL_VERSIONNUM(1, 2, 8)) + { + setpanning_workaround = true; + fprintf(stderr, "\n" + "ATTENTION: You are using an old version of SDL_mixer!\n" + " This version has a bug that may cause " + "your sound to stutter.\n" + " Please upgrade to a newer version!\n" + "\n"); + } + } + Mix_AllocateChannels(NUM_CHANNELS); - + SDL_PauseAudio(0); sound_initialized = true; diff --git a/src/i_system.c b/src/i_system.c index cd8ddcee..0a856ca9 100644 --- a/src/i_system.c +++ b/src/i_system.c @@ -189,7 +189,7 @@ byte *I_ZoneBase (int *size) // Specify the heap size, in MiB (default 16). // - p = M_CheckParm("-mb"); + p = M_CheckParmWithArgs("-mb", 1); if (p > 0) { @@ -327,9 +327,9 @@ void I_Error (char *error, ...) // Message first. va_start(argptr, error); - fprintf(stderr, "\nError: "); + //fprintf(stderr, "\nError: "); vfprintf(stderr, error, argptr); - fprintf(stderr, "\n"); + fprintf(stderr, "\n\n"); va_end(argptr); fflush(stderr); @@ -362,7 +362,7 @@ void I_Error (char *error, ...) msgbuf, strlen(msgbuf) + 1, wmsgbuf, sizeof(wmsgbuf)); - MessageBoxW(NULL, wmsgbuf, L"Error", MB_OK); + MessageBoxW(NULL, wmsgbuf, L"", MB_OK); } #endif diff --git a/src/i_video.c b/src/i_video.c index 8c2cfeac..6bf2f179 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -31,6 +31,11 @@ #include <math.h> #include <string.h> +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + #include "icon.c" #include "config.h" @@ -139,6 +144,12 @@ static SDL_Surface *screen; static char *window_title = ""; +// Intermediate 8-bit buffer that we draw to instead of 'screen'. +// This is used when we are rendering in 32-bit screen mode. +// When in a real 8-bit screen mode, screenbuffer == screen. + +static SDL_Surface *screenbuffer = NULL; + // palette static SDL_Color palette[256]; @@ -172,6 +183,10 @@ static boolean native_surface; static int screen_width = SCREENWIDTH; static int screen_height = SCREENHEIGHT; +// Color depth. + +int screen_bpp = 8; + // Automatically adjust video settings if the selected mode is // not a valid video mode. @@ -911,17 +926,18 @@ static boolean BlitArea(int x1, int y1, int x2, int y2) return true; } - x_offset = (screen->w - screen_mode->width) / 2; - y_offset = (screen->h - screen_mode->height) / 2; + x_offset = (screenbuffer->w - screen_mode->width) / 2; + y_offset = (screenbuffer->h - screen_mode->height) / 2; - if (SDL_LockSurface(screen) >= 0) + if (SDL_LockSurface(screenbuffer) >= 0) { I_InitScale(I_VideoBuffer, - (byte *) screen->pixels + (y_offset * screen->pitch) - + x_offset, - screen->pitch); + (byte *) screenbuffer->pixels + + (y_offset * screenbuffer->pitch) + + x_offset, + screenbuffer->pitch); result = screen_mode->DrawScreen(x1, y1, x2, y2); - SDL_UnlockSurface(screen); + SDL_UnlockSurface(screenbuffer); } else { @@ -1055,19 +1071,37 @@ void I_FinishUpdate (void) // draw to screen BlitArea(0, 0, SCREENWIDTH, SCREENHEIGHT); - - // If we have a palette to set, the act of setting the palette - // updates the screen if (palette_to_set) { - SDL_SetColors(screen, palette, 0, 256); + SDL_SetColors(screenbuffer, palette, 0, 256); palette_to_set = false; + + // In native 8-bit mode, if we have a palette to set, the act + // of setting the palette updates the screen + + if (screenbuffer == screen) + { + return; + } } - else + + // In 8in32 mode, we must blit from the fake 8-bit screen buffer + // to the real screen before doing a screen flip. + + if (screenbuffer != screen) { - SDL_Flip(screen); + SDL_Rect dst_rect; + + // Center the buffer within the full screen space. + + dst_rect.x = (screen->w - screenbuffer->w) / 2; + dst_rect.y = (screen->h - screenbuffer->h) / 2; + + SDL_BlitSurface(screenbuffer, NULL, screen, &dst_rect); } + + SDL_Flip(screen); } @@ -1348,15 +1382,61 @@ static void AutoAdjustWindowed(void) } } +// Auto-adjust to a valid color depth. + +static void AutoAdjustColorDepth(void) +{ + SDL_Rect **modes; + SDL_PixelFormat format; + const SDL_VideoInfo *info; + int flags; + + if (fullscreen) + { + flags = SDL_FULLSCREEN; + } + else + { + flags = 0; + } + + format.BitsPerPixel = screen_bpp; + format.BytesPerPixel = (screen_bpp + 7) / 8; + + // Are any screen modes supported at the configured color depth? + + modes = SDL_ListModes(&format, flags); + + // If not, we must autoadjust to something sensible. + + if (modes == NULL) + { + printf("I_InitGraphics: %ibpp color depth not supported.\n", + screen_bpp); + + info = SDL_GetVideoInfo(); + + if (info != NULL && info->vfmt != NULL) + { + screen_bpp = info->vfmt->BitsPerPixel; + } + } +} + // If the video mode set in the configuration file is not available, // try to choose a different mode. static void I_AutoAdjustSettings(void) { - int old_screen_w, old_screen_h; + int old_screen_w, old_screen_h, old_screen_bpp; old_screen_w = screen_width; old_screen_h = screen_height; + old_screen_bpp = screen_bpp; + + // Possibly adjust color depth. + + AutoAdjustColorDepth(); // If we are running fullscreen, try to autoadjust to a valid fullscreen // mode. If this is impossible, switch to windowed. @@ -1375,10 +1455,11 @@ static void I_AutoAdjustSettings(void) // Have the settings changed? Show a message. - if (screen_width != old_screen_w || screen_height != old_screen_h) + if (screen_width != old_screen_w || screen_height != old_screen_h + || screen_bpp != old_screen_bpp) { - printf("I_InitGraphics: Auto-adjusted to %ix%i.\n", - screen_width, screen_height); + printf("I_InitGraphics: Auto-adjusted to %ix%ix%ibpp.\n", + screen_width, screen_height, screen_bpp); printf("NOTE: Your video settings have been adjusted. " "To disable this behavior,\n" @@ -1544,7 +1625,7 @@ static void CheckCommandLine(void) // Specify the screen width, in pixels. // - i = M_CheckParm("-width"); + i = M_CheckParmWithArgs("-width", 1); if (i > 0) { @@ -1558,7 +1639,7 @@ static void CheckCommandLine(void) // Specify the screen height, in pixels. // - i = M_CheckParm("-height"); + i = M_CheckParmWithArgs("-height", 1); if (i > 0) { @@ -1567,12 +1648,39 @@ static void CheckCommandLine(void) //! // @category video + // @arg <bpp> + // + // Specify the color depth of the screen, in bits per pixel. + // + + i = M_CheckParmWithArgs("-bpp", 1); + + if (i > 0) + { + screen_bpp = atoi(myargv[i + 1]); + } + + // Because we love Eternity: + + //! + // @category video + // + // Set the color depth of the screen to 32 bits per pixel. + // + + if (M_CheckParm("-8in32")) + { + screen_bpp = 32; + } + + //! + // @category video // @arg <WxY> // // Specify the screen mode (when running fullscreen) or the window // dimensions (when running in windowed mode). - i = M_CheckParm("-geometry"); + i = M_CheckParmWithArgs("-geometry", 1); if (i > 0) { @@ -1743,6 +1851,14 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE); + // If we are already running and in a true color mode, we need + // to free the screenbuffer surface before setting the new mode. + + if (screenbuffer != NULL && screen != screenbuffer) + { + SDL_FreeSurface(screenbuffer); + } + // Generate lookup tables before setting the video mode. if (mode != NULL && mode->InitMode != NULL) @@ -1752,7 +1868,12 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) // Set the video mode. - flags |= SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF; + flags |= SDL_SWSURFACE | SDL_DOUBLEBUF; + + if (screen_bpp == 8) + { + flags |= SDL_HWPALETTE; + } if (fullscreen) { @@ -1760,18 +1881,30 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) } else { + // In windowed mode, the window can be resized while the game is + // running. This feature is disabled on OS X, as it adds an ugly + // scroll handle to the corner of the screen. + +#ifndef __MACOSX__ flags |= SDL_RESIZABLE; +#endif // villsa - center window SDL_putenv("SDL_VIDEO_CENTERED=1"); } - screen = SDL_SetVideoMode(w, h, 8, flags); + screen = SDL_SetVideoMode(w, h, screen_bpp, flags); if (screen == NULL) { - I_Error("Error setting video mode: %s\n", SDL_GetError()); + I_Error("Error setting video mode %ix%ix%ibpp: %s\n", + w, h, screen_bpp, SDL_GetError()); } + // Blank out the full screen area in case there is any junk in + // the borders that won't otherwise be overwritten. + + SDL_FillRect(screen, NULL, 0); + // If mode was not set, it must be set now that we know the // screen size. @@ -1793,6 +1926,22 @@ static void SetVideoMode(screen_mode_t *mode, int w, int h) } } + // Create the screenbuffer surface; if we have a real 8-bit palettized + // screen, then we can use the screen as the screenbuffer. + + if (screen->format->BitsPerPixel == 8) + { + screenbuffer = screen; + } + else + { + screenbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, + mode->width, mode->height, 8, + 0, 0, 0, 0); + + SDL_FillRect(screenbuffer, NULL, 0); + } + // Save screen mode. screen_mode = mode; @@ -1910,24 +2059,13 @@ void I_InitGraphics(void) // Start with a clear black screen // (screen will be flipped after we set the palette) - if (SDL_LockSurface(screen) >= 0) - { - byte *screenpixels; - int y; - - screenpixels = (byte *) screen->pixels; - - for (y=0; y<screen->h; ++y) - memset(screenpixels + screen->pitch * y, 0, screen->w); - - SDL_UnlockSurface(screen); - } + SDL_FillRect(screenbuffer, NULL, 0); // Set the palette doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE); I_SetPalette(doompal); - SDL_SetColors(screen, palette, 0, 256); + SDL_SetColors(screenbuffer, palette, 0, 256); CreateCursors(); @@ -1949,7 +2087,8 @@ void I_InitGraphics(void) // Likewise if the screen pitch is not the same as the width // If we have to multiply, drawing is done to a separate 320x200 buf - native_surface = !SDL_MUSTLOCK(screen) + native_surface = screen == screenbuffer + && !SDL_MUSTLOCK(screen) && screen_mode == &mode_scale_1x && screen->pitch == SCREENWIDTH && aspect_ratio_correct; @@ -2013,6 +2152,7 @@ void I_BindVideoVariables(void) M_BindVariable("startup_delay", &startup_delay); M_BindVariable("screen_width", &screen_width); M_BindVariable("screen_height", &screen_height); + M_BindVariable("screen_bpp", &screen_bpp); M_BindVariable("grabmouse", &grabmouse); M_BindVariable("mouse_acceleration", &mouse_acceleration); M_BindVariable("mouse_threshold", &mouse_threshold); @@ -2020,5 +2160,26 @@ void I_BindVideoVariables(void) M_BindVariable("usegamma", &usegamma); M_BindVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping); M_BindVariable("novert", &novert); + + // Windows Vista or later? Set screen color depth to + // 32 bits per pixel, as 8-bit palettized screen modes + // don't work properly in recent versions. + +#if defined(_WIN32) && !defined(_WIN32_WCE) + { + OSVERSIONINFOEX version_info; + + ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); + version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + GetVersionEx((OSVERSIONINFO *) &version_info); + + if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT + && version_info.dwMajorVersion >= 6) + { + screen_bpp = 32; + } + } +#endif } diff --git a/src/i_video.h b/src/i_video.h index 82368967..c3c50c4b 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -116,6 +116,7 @@ void I_EnableLoadingDisk(void); extern char *video_driver; extern boolean screenvisible; + extern float mouse_acceleration; extern int mouse_threshold; extern int vanilla_keyboard_mapping; diff --git a/src/m_argv.c b/src/m_argv.c index 79702e56..59381b65 100644 --- a/src/m_argv.c +++ b/src/m_argv.c @@ -47,13 +47,13 @@ char** myargv; // or 0 if not present // -int M_CheckParm (char *check) +int M_CheckParmWithArgs(char *check, int num_args) { - int i; + int i; - for (i = 1;i<myargc;i++) + for (i = 1; i < myargc - num_args; i++) { - if ( !strcasecmp(check, myargv[i]) ) + if (!strcasecmp(check, myargv[i])) return i; } @@ -72,6 +72,11 @@ boolean M_ParmExists(char *check) return M_CheckParm(check) != 0; } +int M_CheckParm(char *check) +{ + return M_CheckParmWithArgs(check, 0); +} + #define MAXARGVS 100 static void LoadResponseFile(int argv_index) @@ -88,7 +93,7 @@ static void LoadResponseFile(int argv_index) response_filename = myargv[argv_index] + 1; // Read the response file into memory - handle = fopen(response_filename, "r"); + handle = fopen(response_filename, "rb"); if (handle == NULL) { diff --git a/src/m_argv.h b/src/m_argv.h index 859f93e4..2fb76a2a 100644 --- a/src/m_argv.h +++ b/src/m_argv.h @@ -40,6 +40,10 @@ extern char** myargv; // in the arg list (0 if not found). int M_CheckParm (char* check); +// Same as M_CheckParm, but checks that num_args arguments are available +// following the specified argument. +int M_CheckParmWithArgs(char *check, int num_args); + void M_FindResponseFile(void); // Parameter has been specified? diff --git a/src/m_config.c b/src/m_config.c index 8332750b..bda9828c 100644 --- a/src/m_config.c +++ b/src/m_config.c @@ -645,6 +645,12 @@ static default_t extra_defaults_list[] = CONFIG_VARIABLE_INT(screen_height), //! + // Color depth of the screen, in bits. + // + + CONFIG_VARIABLE_INT(screen_bpp), + + //! // If this is non-zero, the mouse will be "grabbed" when running // in windowed mode so that it can be used as an input device. // When running full screen, this has no effect. @@ -1288,8 +1294,18 @@ static void SaveDefaultCollection(default_collection_t *collection) v = * (int *) defaults[i].location; - if (defaults[i].untranslated - && v == defaults[i].original_translated) + if (v == KEY_RSHIFT) + { + // Special case: for shift, force scan code for + // right shift, as this is what Vanilla uses. + // This overrides the change check below, to fix + // configuration files made by old versions that + // mistakenly used the scan code for left shift. + + v = 54; + } + else if (defaults[i].untranslated + && v == defaults[i].original_translated) { // Has not been changed since the last time we // read the config file. @@ -1507,9 +1523,9 @@ void M_LoadDefaults (void) // configuration file (for Doom) is named default.cfg. // - i = M_CheckParm ("-config"); + i = M_CheckParmWithArgs("-config", 1); - if (i && i<myargc-1) + if (i) { doom_defaults.filename = myargv[i+1]; printf (" default file: %s\n",doom_defaults.filename); @@ -1530,9 +1546,9 @@ void M_LoadDefaults (void) // configuration file for Doom is named chocolate-doom.cfg. // - i = M_CheckParm("-extraconfig"); + i = M_CheckParmWithArgs("-extraconfig", 1); - if (i && i<myargc-1) + if (i) { extra_defaults.filename = myargv[i+1]; printf(" extra configuration file: %s\n", diff --git a/src/net_client.c b/src/net_client.c index a1697944..ffc9b49b 100644 --- a/src/net_client.c +++ b/src/net_client.c @@ -28,13 +28,12 @@ #include "config.h" #include "doomtype.h" -#include "doomstat.h" #include "deh_main.h" #include "deh_str.h" -#include "g_game.h" #include "i_system.h" #include "i_timer.h" #include "m_argv.h" +#include "m_fixed.h" #include "m_config.h" #include "net_client.h" #include "net_common.h" @@ -47,6 +46,8 @@ #include "w_checksum.h" #include "w_wad.h" +extern void D_ReceiveTic(ticcmd_t *ticcmds, boolean *playeringame); + typedef enum { // waiting for the game to start @@ -105,6 +106,10 @@ static net_clientstate_t client_state; static net_addr_t *server_addr; static net_context_t *client_context; +// game settings, as received from the server when the game started + +static net_gamesettings_t settings; + // true if the client code is in use boolean net_client_connected; @@ -152,6 +157,10 @@ boolean net_waiting_for_start = false; char *net_player_name = NULL; +// Connected but not participating in the game (observer) + +boolean drone = false; + // The last ticcmd constructed static ticcmd_t last_ticcmd; @@ -187,53 +196,11 @@ static fixed_t average_latency; #define NET_CL_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b)) -// Called when a player leaves the game - -static void NET_CL_PlayerQuitGame(player_t *player) -{ - static char exitmsg[80]; - - // Do this the same way as Vanilla Doom does, to allow dehacked - // replacements of this message - - strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg)); - exitmsg[sizeof(exitmsg) - 1] = '\0'; - - exitmsg[7] += player - players; - - players[consoleplayer].message = exitmsg; - - // TODO: check if it is sensible to do this: - - if (demorecording) - { - G_CheckDemoStatus (); - } -} - // Called when we become disconnected from the server static void NET_CL_Disconnected(void) { - int i; - - // In drone mode, the game cannot continue once disconnected. - - if (drone) - { - I_Error("Disconnected from server in drone mode."); - } - - // disconnected from server - - players[consoleplayer].message = "Disconnected from server"; - printf("Disconnected from server.\n"); - - for (i=0; i<MAXPLAYERS; ++i) - { - if (i != consoleplayer) - playeringame[i] = false; - } + D_ReceiveTic(NULL, NULL); } // Expand a net_full_ticcmd_t, applying the diffs in cmd->cmds as @@ -241,7 +208,8 @@ static void NET_CL_Disconnected(void) // the d_net.c structures (netcmds/nettics) and save the new ticcmd // back into recvwindow_cmd_base. -static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq) +static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq, + ticcmd_t *ticcmds) { int latency; fixed_t adjustment; @@ -303,38 +271,25 @@ static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq) for (i=0; i<MAXPLAYERS; ++i) { - if (i == consoleplayer && !drone) + if (i == settings.consoleplayer && !drone) { continue; } - if (playeringame[i] && !cmd->playeringame[i]) - { - NET_CL_PlayerQuitGame(&players[i]); - } - - playeringame[i] = cmd->playeringame[i]; - - if (playeringame[i]) + if (cmd->playeringame[i]) { net_ticdiff_t *diff; - ticcmd_t ticcmd; diff = &cmd->cmds[i]; // Use the ticcmd diff to patch the previous ticcmd to // the new ticcmd - NET_TiccmdPatch(&recvwindow_cmd_base[i], diff, &ticcmd); - - // Save in d_net.c structures - - netcmds[i][nettics[i] % BACKUPTICS] = ticcmd; - ++nettics[i]; + NET_TiccmdPatch(&recvwindow_cmd_base[i], diff, &ticcmds[i]); // Store a copy for next time - recvwindow_cmd_base[i] = ticcmd; + recvwindow_cmd_base[i] = ticcmds[i]; } } } @@ -343,11 +298,15 @@ static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq) static void NET_CL_AdvanceWindow(void) { + ticcmd_t ticcmds[MAXPLAYERS]; + while (recvwindow[0].active) { // Expand tic diff data into d_net.c structures - NET_CL_ExpandFullTiccmd(&recvwindow[0].cmd, recvwindow_start); + NET_CL_ExpandFullTiccmd(&recvwindow[0].cmd, recvwindow_start, + ticcmds); + D_ReceiveTic(ticcmds, recvwindow[0].cmd.playeringame); // Advance the window @@ -375,66 +334,9 @@ static void NET_CL_Shutdown(void) } } -void NET_CL_StartGame(void) +void NET_CL_StartGame(net_gamesettings_t *settings) { net_packet_t *packet; - net_gamesettings_t settings; - int i; - - // Fill in game settings structure with appropriate parameters - // for the new game - - settings.deathmatch = deathmatch; - settings.episode = startepisode; - settings.map = startmap; - settings.skill = startskill; - settings.loadgame = startloadgame; - settings.gameversion = gameversion; - settings.nomonsters = nomonsters; - settings.fast_monsters = fastparm; - settings.respawn_monsters = respawnparm; - settings.timelimit = timelimit; - - //! - // @category net - // - // Use original game sync code. - // - - if (M_CheckParm("-oldsync") > 0) - settings.new_sync = 0; - else - settings.new_sync = 1; - - //! - // @category net - // @arg <n> - // - // Send n extra tics in every packet as insurance against dropped - // packets. - // - - i = M_CheckParm("-extratics"); - - if (i > 0) - settings.extratics = atoi(myargv[i+1]); - else - settings.extratics = 1; - - //! - // @category net - // @arg <n> - // - // Reduce the resolution of the game by a factor of n, reducing - // the amount of network bandwidth needed. - // - - i = M_CheckParm("-dup"); - - if (i > 0) - settings.ticdup = atoi(myargv[i+1]); - else - settings.ticdup = 1; // Start from a ticcmd of all zeros @@ -445,7 +347,7 @@ void NET_CL_StartGame(void) packet = NET_Conn_NewReliable(&client_connection, NET_PACKET_TYPE_GAMESTART); - NET_WriteSettings(packet, &settings); + NET_WriteSettings(packet, settings); } static void NET_CL_SendGameDataACK(void) @@ -455,7 +357,7 @@ static void NET_CL_SendGameDataACK(void) packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_ACK); - NET_WriteInt8(packet, (gametic / ticdup) & 0xff); + NET_WriteInt8(packet, recvwindow_start & 0xff); NET_Conn_SendPacket(&client_connection, packet); @@ -487,7 +389,7 @@ static void NET_CL_SendTics(int start, int end) // Write the start tic and number of tics. Send only the low byte // of start - it can be inferred by the server. - NET_WriteInt8(packet, (gametic / ticdup) & 0xff); + NET_WriteInt8(packet, recvwindow_start & 0xff); NET_WriteInt8(packet, start & 0xff); NET_WriteInt8(packet, end - start + 1); @@ -501,7 +403,7 @@ static void NET_CL_SendTics(int start, int end) NET_WriteInt16(packet, average_latency / FRACUNIT); - NET_WriteTiccmdDiff(packet, &sendobj->cmd, lowres_turn); + NET_WriteTiccmdDiff(packet, &sendobj->cmd, settings.lowres_turn); } // Send the packet @@ -541,7 +443,7 @@ void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic) // Send to server. - starttic = maketic - extratics; + starttic = maketic - settings.extratics; endtic = maketic; if (starttic < 0) @@ -632,14 +534,7 @@ static void NET_CL_ParseWaitingData(net_packet_t *packet) static void NET_CL_ParseGameStart(net_packet_t *packet) { - net_gamesettings_t settings; - unsigned int num_players; - signed int player_number; - unsigned int i; - - if (!NET_ReadInt8(packet, &num_players) - || !NET_ReadSInt8(packet, &player_number) - || !NET_ReadSettings(packet, &settings)) + if (!NET_ReadSettings(packet, &settings)) { return; } @@ -649,14 +544,15 @@ static void NET_CL_ParseGameStart(net_packet_t *packet) return; } - if (num_players > MAXPLAYERS || player_number >= (signed int) num_players) + if (settings.num_players > MAXPLAYERS + || settings.consoleplayer >= (signed int) settings.num_players) { // insane values return; } - if ((drone && player_number >= 0) - || (!drone && player_number < 0)) + if ((drone && settings.consoleplayer >= 0) + || (!drone && settings.consoleplayer < 0)) { // Invalid player number: must be positive for real players, // negative for drones @@ -664,49 +560,8 @@ static void NET_CL_ParseGameStart(net_packet_t *packet) return; } - // Start the game - - if (!drone) - { - consoleplayer = player_number; - } - else - { - consoleplayer = 0; - } - - for (i=0; i<MAXPLAYERS; ++i) - { - playeringame[i] = i < num_players; - } - client_state = CLIENT_STATE_IN_GAME; - deathmatch = settings.deathmatch; - ticdup = settings.ticdup; - extratics = settings.extratics; - startepisode = settings.episode; - startmap = settings.map; - startskill = settings.skill; - startloadgame = settings.loadgame; - lowres_turn = settings.lowres_turn; - nomonsters = settings.nomonsters; - fastparm = settings.fast_monsters; - respawnparm = settings.respawn_monsters; - net_cl_new_sync = settings.new_sync != 0; - timelimit = settings.timelimit; - - if (net_cl_new_sync == false) - { - printf("Syncing netgames like Vanilla Doom.\n"); - } - - if (lowres_turn) - { - printf("NOTE: Turning resolution is reduced; this is probably " - "because there is a client recording a Vanilla demo.\n"); - } - // Clear the receive window memset(recvwindow, 0, sizeof(recvwindow)); @@ -716,9 +571,6 @@ static void NET_CL_ParseGameStart(net_packet_t *packet) // Clear the send queue memset(&send_queue, 0x00, sizeof(send_queue)); - - netgame = true; - autostart = true; } static void NET_CL_SendResendRequest(int start, int end) @@ -865,7 +717,7 @@ static void NET_CL_ParseGameData(net_packet_t *packet) index = seq - recvwindow_start + i; - if (!NET_ReadFullTiccmd(packet, &cmd, lowres_turn)) + if (!NET_ReadFullTiccmd(packet, &cmd, settings.lowres_turn)) { return; } @@ -1106,7 +958,7 @@ void NET_CL_Run(void) } } -static void NET_CL_SendSYN(void) +static void NET_CL_SendSYN(net_connect_data_t *data) { net_packet_t *packet; @@ -1114,10 +966,7 @@ static void NET_CL_SendSYN(void) NET_WriteInt16(packet, NET_PACKET_TYPE_SYN); NET_WriteInt32(packet, NET_MAGIC_NUMBER); NET_WriteString(packet, PACKAGE_STRING); - NET_WriteInt16(packet, gamemode); - NET_WriteInt16(packet, gamemission); - NET_WriteInt8(packet, lowres_turn); - NET_WriteInt8(packet, drone); + NET_WriteConnectData(packet, data); NET_WriteMD5Sum(packet, net_local_wad_md5sum); NET_WriteMD5Sum(packet, net_local_deh_md5sum); NET_WriteInt8(packet, net_local_is_freedoom); @@ -1128,20 +977,13 @@ static void NET_CL_SendSYN(void) // connect to a server -boolean NET_CL_Connect(net_addr_t *addr) +boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data) { int start_time; int last_send_time; server_addr = addr; - // Are we recording a demo? Possibly set lowres turn mode - - if (M_CheckParm("-record") > 0 && M_CheckParm("-longtics") == 0) - { - lowres_turn = true; - } - // Read checksums of our WAD directory and dehacked information W_Checksum(net_local_wad_md5sum); @@ -1155,7 +997,7 @@ boolean NET_CL_Connect(net_addr_t *addr) // necessary module client_context = NET_NewContext(); - + // initialize module for client mode if (!addr->module->InitClient()) @@ -1185,7 +1027,7 @@ boolean NET_CL_Connect(net_addr_t *addr) if (nowtime - last_send_time > 1000 || last_send_time < 0) { - NET_CL_SendSYN(); + NET_CL_SendSYN(data); last_send_time = nowtime; } @@ -1199,7 +1041,7 @@ boolean NET_CL_Connect(net_addr_t *addr) // run client code NET_CL_Run(); - + // run the server, just incase we are doing a loopback // connect @@ -1215,6 +1057,7 @@ boolean NET_CL_Connect(net_addr_t *addr) // connected ok! client_state = CLIENT_STATE_WAITING_START; + drone = data->drone; return true; } @@ -1223,9 +1066,23 @@ boolean NET_CL_Connect(net_addr_t *addr) // failed to connect NET_CL_Shutdown(); - + + return false; + } +} + +// read game settings received from server + +boolean NET_CL_GetSettings(net_gamesettings_t *_settings) +{ + if (client_state != CLIENT_STATE_IN_GAME) + { return false; } + + memcpy(_settings, &settings, sizeof(net_gamesettings_t)); + + return true; } // disconnect from the server diff --git a/src/net_client.h b/src/net_client.h index 078a19a2..b071d32a 100644 --- a/src/net_client.h +++ b/src/net_client.h @@ -31,12 +31,13 @@ #define MAXPLAYERNAME 30 -boolean NET_CL_Connect(net_addr_t *addr); +boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data); void NET_CL_Disconnect(void); void NET_CL_Run(void); void NET_CL_Init(void); -void NET_CL_StartGame(); +void NET_CL_StartGame(net_gamesettings_t *settings); void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic); +boolean NET_CL_GetSettings(net_gamesettings_t *_settings); void NET_Init(void); void NET_BindVariables(void); @@ -59,6 +60,7 @@ extern md5_digest_t net_local_wad_md5sum; extern md5_digest_t net_local_deh_md5sum; extern unsigned int net_local_is_freedoom; +extern boolean drone; #endif /* #ifndef NET_CLIENT_H */ diff --git a/src/net_dedicated.c b/src/net_dedicated.c index b47a7924..d8e50731 100644 --- a/src/net_dedicated.c +++ b/src/net_dedicated.c @@ -74,8 +74,8 @@ void NET_DedicatedServer(void) CheckForClientOptions(); NET_SV_Init(); - NET_SV_AddModule(&net_sdl_module); + NET_SV_RegisterWithMaster(); while (true) { diff --git a/src/net_defs.h b/src/net_defs.h index a5fddc4d..1fa9a9af 100644 --- a/src/net_defs.h +++ b/src/net_defs.h @@ -128,6 +128,30 @@ typedef enum NET_PACKET_TYPE_QUERY_RESPONSE, } net_packet_type_t; +typedef enum +{ + NET_MASTER_PACKET_TYPE_ADD, + NET_MASTER_PACKET_TYPE_ADD_RESPONSE, + NET_MASTER_PACKET_TYPE_QUERY, + NET_MASTER_PACKET_TYPE_QUERY_RESPONSE +} net_master_packet_type_t; + +// Settings specified when the client connects to the server. + +typedef struct +{ + int gamemode; + int gamemission; + int lowres_turn; + int drone; + // TODO: is_freedoom in here? WAD/DEH checksums? + // TODO: [Hexen] Requested player class + +} net_connect_data_t; + +// Game settings sent by client to server when initiating game start, +// and received from the server by clients when the game starts. + typedef struct { int ticdup; @@ -144,6 +168,15 @@ typedef struct int new_sync; int timelimit; int loadgame; + + // These fields are only used by the server when sending a game + // start message: + + int num_players; + int consoleplayer; + + // TODO: [Hexen] Array of player classes, one for each player. + } net_gamesettings_t; #define NET_TICDIFF_FORWARD (1 << 0) diff --git a/src/net_gui.c b/src/net_gui.c index 8c848d1c..f2c4f1e5 100644 --- a/src/net_gui.c +++ b/src/net_gui.c @@ -53,9 +53,11 @@ static void EscapePressed(TXT_UNCAST_ARG(widget), void *unused) I_Quit(); } -static void StartGame(TXT_UNCAST_ARG(widget), void *unused) +static void StartGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(settings)) { - NET_CL_StartGame(); + TXT_CAST_ARG(net_gamesettings_t, settings); + + NET_CL_StartGame(settings); } static void BuildGUI(void) @@ -101,7 +103,7 @@ static void BuildGUI(void) TXT_SetWindowAction(window, TXT_HORIZ_LEFT, cancel); } -static void UpdateGUI(void) +static void UpdateGUI(net_gamesettings_t *settings) { txt_window_action_t *startgame; char buf[50]; @@ -144,7 +146,7 @@ static void UpdateGUI(void) if (net_client_controller) { startgame = TXT_NewWindowAction(' ', "Start game"); - TXT_SignalConnect(startgame, "pressed", StartGame, NULL); + TXT_SignalConnect(startgame, "pressed", StartGame, settings); } else { @@ -259,7 +261,7 @@ static void CheckMD5Sums(void) had_warning = true; } -void NET_WaitForStart(void) +void NET_WaitForStart(net_gamesettings_t *settings) { if (!TXT_Init()) { @@ -268,13 +270,13 @@ void NET_WaitForStart(void) } I_SetWindowTitle("Waiting for game start"); - I_SetWindowIcon(); + //I_SetWindowIcon(); BuildGUI(); while (net_waiting_for_start) { - UpdateGUI(); + UpdateGUI(settings); CheckMD5Sums(); TXT_DispatchEvents(); @@ -285,7 +287,7 @@ void NET_WaitForStart(void) if (!net_client_connected) { - I_Error("Disconnected from server"); + I_Error("Lost connection to server"); } TXT_Sleep(100); diff --git a/src/net_gui.h b/src/net_gui.h index fdcc81be..9d40b0d0 100644 --- a/src/net_gui.h +++ b/src/net_gui.h @@ -30,7 +30,7 @@ #include "doomtype.h" -extern void NET_WaitForStart(); +extern void NET_WaitForStart(net_gamesettings_t *settings); #endif /* #ifndef NET_GUI_H */ diff --git a/src/net_loop.c b/src/net_loop.c index 9f371bcb..acdc2cb6 100644 --- a/src/net_loop.c +++ b/src/net_loop.c @@ -137,9 +137,16 @@ static void NET_CL_FreeAddress(net_addr_t *addr) static net_addr_t *NET_CL_ResolveAddress(char *address) { - client_addr.module = &net_loop_client_module; + if (address == NULL) + { + client_addr.module = &net_loop_client_module; - return &client_addr; + return &client_addr; + } + else + { + return NULL; + } } net_module_t net_loop_client_module = @@ -206,8 +213,15 @@ static void NET_SV_FreeAddress(net_addr_t *addr) static net_addr_t *NET_SV_ResolveAddress(char *address) { - server_addr.module = &net_loop_server_module; - return &server_addr; + if (address == NULL) + { + server_addr.module = &net_loop_server_module; + return &server_addr; + } + else + { + return NULL; + } } net_module_t net_loop_server_module = diff --git a/src/net_query.c b/src/net_query.c index b50b4292..ae56dea6 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -37,50 +37,166 @@ #include "net_structrw.h" #include "net_sdl.h" -typedef struct +// DNS address of the Internet master server. + +#define MASTER_SERVER_ADDRESS "master.chocolate-doom.org:2342" + +// Time to wait for a response before declaring a timeout. + +#define QUERY_TIMEOUT_SECS 2 + +// Number of query attempts to make before giving up on a server. + +#define QUERY_MAX_ATTEMPTS 3 + +typedef enum { + QUERY_TARGET_SERVER, // Normal server target. + QUERY_TARGET_MASTER, // The master server. + QUERY_TARGET_BROADCAST // Send a broadcast query +} query_target_type_t; + +typedef enum +{ + QUERY_TARGET_QUEUED, // Query not yet sent + QUERY_TARGET_QUERIED, // Query sent, waiting response + QUERY_TARGET_RESPONDED, // Response received + QUERY_TARGET_NO_RESPONSE +} query_target_state_t; + +typedef struct +{ + query_target_type_t type; + query_target_state_t state; net_addr_t *addr; net_querydata_t data; -} queryresponse_t; + unsigned int ping_time; + unsigned int query_time; + unsigned int query_attempts; + boolean printed; +} query_target_t; + +// Transmit a query packet + +static boolean registered_with_master = false; static net_context_t *query_context; -static queryresponse_t *responders; -static int num_responses; +static query_target_t *targets; +static int num_targets; + +static boolean query_loop_running = false; +static boolean printed_header = false; + +// Resolve the master server address. + +net_addr_t *NET_Query_ResolveMaster(net_context_t *context) +{ + net_addr_t *addr; + + addr = NET_ResolveAddress(context, MASTER_SERVER_ADDRESS); + + if (addr == NULL) + { + fprintf(stderr, "Warning: Failed to resolve address " + "for master server: %s\n", MASTER_SERVER_ADDRESS); + } + + return addr; +} -// Add a new address to the list of hosts that has responded +// Send a registration packet to the master server to register +// ourselves with the global list. -static queryresponse_t *AddResponder(net_addr_t *addr, - net_querydata_t *data) +void NET_Query_AddToMaster(net_addr_t *master_addr) { - queryresponse_t *response; + net_packet_t *packet; + + packet = NET_NewPacket(10); + NET_WriteInt16(packet, NET_MASTER_PACKET_TYPE_ADD); + NET_SendPacket(master_addr, packet); + NET_FreePacket(packet); +} + +// Process a packet received from the master server. + +void NET_Query_MasterResponse(net_packet_t *packet) +{ + unsigned int packet_type; + unsigned int result; + + if (!NET_ReadInt16(packet, &packet_type) + || !NET_ReadInt16(packet, &result)) + { + return; + } + + if (packet_type == NET_MASTER_PACKET_TYPE_ADD_RESPONSE) + { + if (result != 0) + { + // Only show the message once. + + if (!registered_with_master) + { + printf("Registered with master server at %s\n", + MASTER_SERVER_ADDRESS); + registered_with_master = true; + } + } + else + { + // Always show rejections. - responders = realloc(responders, - sizeof(queryresponse_t) * (num_responses + 1)); + printf("Failed to register with master server at %s\n", + MASTER_SERVER_ADDRESS); + } + } +} - response = &responders[num_responses]; - response->addr = addr; - response->data = *data; - ++num_responses; +// Send a query to the master server. + +static void NET_Query_SendMasterQuery(net_addr_t *addr) +{ + net_packet_t *packet; - return response; + packet = NET_NewPacket(10); + NET_WriteInt16(packet, NET_MASTER_PACKET_TYPE_QUERY); + NET_SendPacket(addr, packet); + NET_FreePacket(packet); } -// Returns true if the reply is from a host that has not previously -// responded. +// Given the specified address, find the target associated. If no +// target is found, and 'create' is true, a new target is created. -static boolean CheckResponder(net_addr_t *addr) +static query_target_t *GetTargetForAddr(net_addr_t *addr, boolean create) { + query_target_t *target; int i; - for (i=0; i<num_responses; ++i) + for (i=0; i<num_targets; ++i) { - if (responders[i].addr == addr) + if (targets[i].addr == addr) { - return false; + return &targets[i]; } } - return true; + if (!create) + { + return NULL; + } + + targets = realloc(targets, sizeof(query_target_t) * (num_targets + 1)); + + target = &targets[num_targets]; + target->type = QUERY_TARGET_SERVER; + target->state = QUERY_TARGET_QUEUED; + target->printed = false; + target->query_attempts = 0; + target->addr = addr; + ++num_targets; + + return target; } // Transmit a query packet @@ -104,166 +220,254 @@ static void NET_Query_SendQuery(net_addr_t *addr) NET_FreePacket(request); } -static void formatted_printf(int wide, char *s, ...) +static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet, + net_query_callback_t callback, + void *user_data) { - va_list args; - int i; - - va_start(args, s); - i = vprintf(s, args); - va_end(args); + unsigned int packet_type; + net_querydata_t querydata; + query_target_t *target; + + // Read the header - while (i < wide) + if (!NET_ReadInt16(packet, &packet_type) + || packet_type != NET_PACKET_TYPE_QUERY_RESPONSE) { - putchar(' '); - ++i; - } -} + return; + } -static char *GameDescription(GameMode_t mode, GameMission_t mission) -{ - switch (mode) + // Read query data + + if (!NET_ReadQueryData(packet, &querydata)) { - case shareware: - return "shareware"; - case registered: - return "registered"; - case retail: - return "ultimate"; - case commercial: - if (mission == doom2) - return "doom2"; - else if (mission == pack_tnt) - return "tnt"; - else if (mission == pack_plut) - return "plutonia"; - default: - return "unknown"; + return; } -} -static void PrintHeader(void) -{ - int i; + // Find the target that responded, or potentially add a new target + // if it was not already known (for LAN broadcast search) - formatted_printf(18, "Address"); - formatted_printf(8, "Players"); - puts("Description"); + target = GetTargetForAddr(addr, true); - for (i=0; i<70; ++i) - putchar('='); - putchar('\n'); + if (target->state != QUERY_TARGET_RESPONDED) + { + target->state = QUERY_TARGET_RESPONDED; + memcpy(&target->data, &querydata, sizeof(net_querydata_t)); + + // Calculate RTT. + + target->ping_time = I_GetTimeMS() - target->query_time; + + // Invoke callback to signal that we have a new address. + + callback(addr, &target->data, target->ping_time, user_data); + } } -static void PrintResponse(queryresponse_t *response) +// Parse a response packet from the master server. + +static void NET_Query_ParseMasterResponse(net_addr_t *master_addr, + net_packet_t *packet) { - formatted_printf(18, "%s: ", NET_AddrToString(response->addr)); - formatted_printf(8, "%i/%i", response->data.num_players, - response->data.max_players); + unsigned int packet_type; + query_target_t *target; + char *addr_str; + net_addr_t *addr; - if (response->data.gamemode != indetermined) + // Read the header. We are only interested in query responses. + + if (!NET_ReadInt16(packet, &packet_type) + || packet_type != NET_MASTER_PACKET_TYPE_QUERY_RESPONSE) { - printf("(%s) ", GameDescription(response->data.gamemode, - response->data.gamemission)); + return; } - if (response->data.server_state) + // Read a list of strings containing the addresses of servers + // that the master knows about. + + for (;;) { - printf("(game running) "); + addr_str = NET_ReadString(packet); + + if (addr_str == NULL) + { + break; + } + + // Resolve address and add to targets list if it is not already + // there. + + addr = NET_ResolveAddress(query_context, addr_str); + + if (addr != NULL) + { + GetTargetForAddr(addr, true); + } } - NET_SafePuts(response->data.description); + // Mark the master as having responded. + + target = GetTargetForAddr(master_addr, true); + target->state = QUERY_TARGET_RESPONDED; } -static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet) +static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet, + net_query_callback_t callback, + void *user_data) { - unsigned int packet_type; - net_querydata_t querydata; - queryresponse_t *response; + query_target_t *target; + + // This might be the master server responding. - // Have we already received a packet from this host? + target = GetTargetForAddr(addr, false); - if (!CheckResponder(addr)) + if (target != NULL && target->type == QUERY_TARGET_MASTER) { - return; + NET_Query_ParseMasterResponse(addr, packet); } + else + { + NET_Query_ParseResponse(addr, packet, callback, user_data); + } +} - // Read the header +static void NET_Query_GetResponse(net_query_callback_t callback, + void *user_data) +{ + net_addr_t *addr; + net_packet_t *packet; - if (!NET_ReadInt16(packet, &packet_type) - || packet_type != NET_PACKET_TYPE_QUERY_RESPONSE) + if (NET_RecvPacket(query_context, &addr, &packet)) { - return; + NET_Query_ParsePacket(addr, packet, callback, user_data); + NET_FreePacket(packet); } +} - // Read query data +// Find a target we have not yet queried and send a query. - if (!NET_ReadQueryData(packet, &querydata)) +static void SendOneQuery(void) +{ + unsigned int now; + unsigned int i; + + now = I_GetTimeMS(); + + for (i = 0; i < num_targets; ++i) + { + // Not queried yet? + // Or last query timed out without a response? + + if (targets[i].state == QUERY_TARGET_QUEUED + || (targets[i].state == QUERY_TARGET_QUERIED + && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000)) + { + break; + } + } + + if (i >= num_targets) { return; } - if (num_responses <= 0) + // Found a target to query. Send a query; how to do this depends on + // the target type. + + switch (targets[i].type) { - // If this is the first response, print the table header + case QUERY_TARGET_SERVER: + NET_Query_SendQuery(targets[i].addr); + break; - PrintHeader(); + case QUERY_TARGET_BROADCAST: + NET_Query_SendQuery(NULL); + break; + + case QUERY_TARGET_MASTER: + NET_Query_SendMasterQuery(targets[i].addr); + break; } - response = AddResponder(addr, &querydata); + //printf("Queried %s\n", NET_AddrToString(targets[i].addr)); + targets[i].state = QUERY_TARGET_QUERIED; + targets[i].query_time = I_GetTimeMS(); + ++targets[i].query_attempts; +} + +// Time out servers that have been queried and not responded. - PrintResponse(response); +static void CheckTargetTimeouts(void) +{ + unsigned int i; + unsigned int now; + + now = I_GetTimeMS(); + + for (i = 0; i < num_targets; ++i) + { + // We declare a target to be "no response" when we've sent + // multiple query packets to it (QUERY_MAX_ATTEMPTS) and + // received no response to any of them. + + if (targets[i].state == QUERY_TARGET_QUERIED + && targets[i].query_attempts >= QUERY_MAX_ATTEMPTS + && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000) + { + targets[i].state = QUERY_TARGET_NO_RESPONSE; + } + } } -static void NET_Query_GetResponse(void) +// If all targets have responded or timed out, returns true. + +static boolean AllTargetsDone(void) { - net_addr_t *addr; - net_packet_t *packet; + unsigned int i; - if (NET_RecvPacket(query_context, &addr, &packet)) + for (i = 0; i < num_targets; ++i) { - NET_Query_ParsePacket(addr, packet); - NET_FreePacket(packet); + if (targets[i].state != QUERY_TARGET_RESPONDED + && targets[i].state != QUERY_TARGET_NO_RESPONSE) + { + return false; + } } + + return true; } -static net_addr_t *NET_Query_QueryLoop(net_addr_t *addr, - boolean find_one) +// Stop the query loop + +static void NET_Query_ExitLoop(void) { - int start_time; - int last_send_time; + query_loop_running = false; +} + +// Loop waiting for responses. +// The specified callback is invoked when a new server responds. - last_send_time = -1; - start_time = I_GetTimeMS(); +static void NET_Query_QueryLoop(net_query_callback_t callback, + void *user_data) +{ + query_loop_running = true; - while (I_GetTimeMS() < start_time + 5000) + while (query_loop_running && !AllTargetsDone()) { - // Send a query once every second + // Send a query. This will only send a single query. + // Because of the delay below, this is therefore rate limited. - if (last_send_time < 0 || I_GetTimeMS() > last_send_time + 1000) - { - NET_Query_SendQuery(addr); - last_send_time = I_GetTimeMS(); - } + SendOneQuery(); // Check for a response - NET_Query_GetResponse(); + NET_Query_GetResponse(callback, user_data); - // Found a response? - - if (find_one && num_responses > 0) - break; - // Don't thrash the CPU - - I_Sleep(100); - } - if (num_responses > 0) - return responders[0].addr; - else - return NULL; + I_Sleep(50); + + CheckTargetTimeouts(); + } } void NET_Query_Init(void) @@ -272,51 +476,256 @@ void NET_Query_Init(void) NET_AddModule(query_context, &net_sdl_module); net_sdl_module.InitClient(); - responders = NULL; - num_responses = 0; + targets = NULL; + num_targets = 0; + + printed_header = false; } -void NET_QueryAddress(char *addr) +// Callback that exits the query loop when the first server is found. + +static void NET_Query_ExitCallback(net_addr_t *addr, net_querydata_t *data, + unsigned int ping_time, void *user_data) { - net_addr_t *net_addr; - - NET_Query_Init(); + NET_Query_ExitLoop(); +} - net_addr = NET_ResolveAddress(query_context, addr); +// Search the targets list and find a target that has responded. +// If none have responded, returns NULL. + +static query_target_t *FindFirstResponder(void) +{ + unsigned int i; - if (net_addr == NULL) + for (i = 0; i < num_targets; ++i) { - I_Error("NET_QueryAddress: Host '%s' not found!", addr); + if (targets[i].type == QUERY_TARGET_SERVER + && targets[i].state == QUERY_TARGET_RESPONDED) + { + return &targets[i]; + } } - printf("\nQuerying '%s'...\n\n", addr); + return NULL; +} - if (!NET_Query_QueryLoop(net_addr, true)) +// Return a count of the number of responses. + +static int GetNumResponses(void) +{ + unsigned int i; + int result; + + result = 0; + + for (i = 0; i < num_targets; ++i) { - I_Error("No response from '%s'", addr); + if (targets[i].type == QUERY_TARGET_SERVER + && targets[i].state == QUERY_TARGET_RESPONDED) + { + ++result; + } } - exit(0); + return result; +} + +void NET_QueryAddress(char *addr_str) +{ + net_addr_t *addr; + query_target_t *target; + + NET_Query_Init(); + + addr = NET_ResolveAddress(query_context, addr_str); + + if (addr == NULL) + { + I_Error("NET_QueryAddress: Host '%s' not found!", addr_str); + } + + // Add the address to the list of targets. + + target = GetTargetForAddr(addr, true); + + printf("\nQuerying '%s'...\n", addr_str); + + // Run query loop. + + NET_Query_QueryLoop(NET_Query_ExitCallback, NULL); + + // Check if the target responded. + + if (target->state == QUERY_TARGET_RESPONDED) + { + NET_QueryPrintCallback(addr, &target->data, target->ping_time, NULL); + } + else + { + I_Error("No response from '%s'", addr_str); + } } net_addr_t *NET_FindLANServer(void) { + query_target_t *target; + query_target_t *responder; + + NET_Query_Init(); + + // Add a broadcast target to the list. + + target = GetTargetForAddr(NULL, true); + target->type = QUERY_TARGET_BROADCAST; + + // Run the query loop, and stop at the first target found. + + NET_Query_QueryLoop(NET_Query_ExitCallback, NULL); + + responder = FindFirstResponder(); + + if (responder != NULL) + { + return responder->addr; + } + else + { + return NULL; + } +} + +int NET_LANQuery(net_query_callback_t callback, void *user_data) +{ + query_target_t *target; + NET_Query_Init(); - return NET_Query_QueryLoop(NULL, true); + // Add a broadcast target to the list. + + target = GetTargetForAddr(NULL, true); + target->type = QUERY_TARGET_BROADCAST; + + NET_Query_QueryLoop(callback, user_data); + + return GetNumResponses(); } -void NET_LANQuery(void) +int NET_MasterQuery(net_query_callback_t callback, void *user_data) { + net_addr_t *master; + query_target_t *target; + NET_Query_Init(); - printf("\nSearching for servers on local LAN ...\n\n"); + // Resolve master address and add to targets list. + + master = NET_Query_ResolveMaster(query_context); + + if (master == NULL) + { + return 0; + } + + target = GetTargetForAddr(master, true); + target->type = QUERY_TARGET_MASTER; + + NET_Query_QueryLoop(callback, user_data); + + // Check that we got a response from the master, and display + // a warning if we didn't. + + if (target->state == QUERY_TARGET_NO_RESPONSE) + { + fprintf(stderr, "NET_MasterQuery: no response from master server.\n"); + } + + return GetNumResponses(); +} + +static void formatted_printf(int wide, char *s, ...) +{ + va_list args; + int i; - if (!NET_Query_QueryLoop(NULL, false)) + va_start(args, s); + i = vprintf(s, args); + va_end(args); + + while (i < wide) { - I_Error("No servers found"); + putchar(' '); + ++i; + } +} + +static char *GameDescription(GameMode_t mode, GameMission_t mission) +{ + switch (mode) + { + case shareware: + return "shareware"; + case registered: + return "registered"; + case retail: + return "ultimate"; + case commercial: + if (mission == doom2) + return "doom2"; + else if (mission == pack_tnt) + return "tnt"; + else if (mission == pack_plut) + return "plutonia"; + default: + return "unknown"; + } +} + +static void PrintHeader(void) +{ + int i; + + putchar('\n'); + formatted_printf(5, "Ping"); + formatted_printf(18, "Address"); + formatted_printf(8, "Players"); + puts("Description"); + + for (i=0; i<70; ++i) + putchar('='); + putchar('\n'); +} + +// Callback function that just prints information in a table. + +void NET_QueryPrintCallback(net_addr_t *addr, + net_querydata_t *data, + unsigned int ping_time, + void *user_data) +{ + // If this is the first server, print the header. + + if (!printed_header) + { + PrintHeader(); + printed_header = true; + } + + formatted_printf(5, "%4i", ping_time); + formatted_printf(18, "%s: ", NET_AddrToString(addr)); + formatted_printf(8, "%i/%i", data->num_players, + data->max_players); + + if (data->gamemode != indetermined) + { + printf("(%s) ", GameDescription(data->gamemode, + data->gamemission)); + } + + if (data->server_state) + { + printf("(game running) "); } - exit(0); + NET_SafePuts(data->description); } diff --git a/src/net_query.h b/src/net_query.h index f682d320..01e059cb 100644 --- a/src/net_query.h +++ b/src/net_query.h @@ -27,9 +27,22 @@ #include "net_defs.h" +typedef void (*net_query_callback_t)(net_addr_t *addr, + net_querydata_t *querydata, + unsigned int ping_time, + void *user_data); + +extern int NET_LANQuery(net_query_callback_t callback, void *user_data); +extern int NET_MasterQuery(net_query_callback_t callback, void *user_data); extern void NET_QueryAddress(char *addr); -extern void NET_LANQuery(void); extern net_addr_t *NET_FindLANServer(void); +extern void NET_QueryPrintCallback(net_addr_t *addr, net_querydata_t *data, + unsigned int ping_time, void *user_data); + +extern net_addr_t *NET_Query_ResolveMaster(net_context_t *context); +extern void NET_Query_AddToMaster(net_addr_t *master_addr); +extern void NET_Query_MasterResponse(net_packet_t *packet); + #endif /* #ifndef NET_QUERY_H */ diff --git a/src/net_sdl.c b/src/net_sdl.c index aa7fbd6e..6a4f24dc 100644 --- a/src/net_sdl.c +++ b/src/net_sdl.c @@ -170,7 +170,7 @@ static boolean NET_SDL_InitClient(void) // the default (2342). // - p = M_CheckParm("-port"); + p = M_CheckParmWithArgs("-port", 1); if (p > 0) port = atoi(myargv[p+1]); @@ -196,7 +196,7 @@ static boolean NET_SDL_InitServer(void) { int p; - p = M_CheckParm("-port"); + p = M_CheckParmWithArgs("-port", 1); if (p > 0) port = atoi(myargv[p+1]); diff --git a/src/net_server.c b/src/net_server.c index 904d932e..ae46be4a 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -41,10 +41,15 @@ #include "net_io.h" #include "net_loop.h" #include "net_packet.h" +#include "net_query.h" #include "net_server.h" #include "net_sdl.h" #include "net_structrw.h" +// How often to refresh our registration with the master server. + +#define MASTER_REFRESH_PERIOD 20 * 60 /* 20 minutes */ + typedef enum { // waiting for the game to start @@ -65,6 +70,11 @@ typedef struct int last_send_time; char *name; + // Time that this client connected to the server. + // This is used to determine the controller (oldest client). + + unsigned int connect_time; + // Last time new gamedata was received from this client int last_gamedata_time; @@ -128,6 +138,11 @@ static unsigned int sv_gamemode; static unsigned int sv_gamemission; static net_gamesettings_t sv_settings; +// For registration with master server: + +static net_addr_t *master_server = NULL; +static unsigned int master_refresh_time; + // receive window static unsigned int recvwindow_start; @@ -372,19 +387,29 @@ static void NET_SV_AdvanceWindow(void) static net_client_t *NET_SV_Controller(void) { + net_client_t *best; int i; - // first client in the list is the controller + // Find the oldest client (first to connect). + + best = NULL; for (i=0; i<MAXNETNODES; ++i) { - if (ClientConnected(&clients[i]) && !clients[i].drone) + // Can't be controller? + + if (!ClientConnected(&clients[i]) || clients[i].drone) { - return &clients[i]; + continue; + } + + if (best == NULL || clients[i].connect_time < best->connect_time) + { + best = &clients[i]; } } - return NULL; + return best; } // Given an address, find the corresponding client @@ -424,6 +449,7 @@ static void NET_SV_InitNewClient(net_client_t *client, char *player_name) { client->active = true; + client->connect_time = I_GetTimeMS(); NET_Conn_InitServer(&client->connection, addr); client->addr = addr; client->last_send_time = -1; @@ -447,10 +473,8 @@ static void NET_SV_ParseSYN(net_packet_t *packet, net_addr_t *addr) { unsigned int magic; - unsigned int cl_gamemode, cl_gamemission; - unsigned int cl_recording_lowres; - unsigned int cl_drone; unsigned int is_freedoom; + net_connect_data_t data; md5_digest_t deh_md5sum, wad_md5sum; char *player_name; char *client_version; @@ -501,10 +525,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet, // read the game mode and mission - if (!NET_ReadInt16(packet, &cl_gamemode) - || !NET_ReadInt16(packet, &cl_gamemission) - || !NET_ReadInt8(packet, &cl_recording_lowres) - || !NET_ReadInt8(packet, &cl_drone) + if (!NET_ReadConnectData(packet, &data) || !NET_ReadMD5Sum(packet, wad_md5sum) || !NET_ReadMD5Sum(packet, deh_md5sum) || !NET_ReadInt8(packet, &is_freedoom)) @@ -512,7 +533,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet, return; } - if (!D_ValidGameMode(cl_gamemission, cl_gamemode)) + if (!D_ValidGameMode(data.gamemission, data.gamemode)) { return; } @@ -579,7 +600,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet, NET_SV_AssignPlayers(); num_players = NET_SV_NumPlayers(); - if ((!cl_drone && num_players >= MAXPLAYERS) + if ((!data.drone && num_players >= MAXPLAYERS) || NET_SV_NumClients() >= MAXNETNODES) { NET_SV_SendReject(addr, "Server is full!"); @@ -592,10 +613,10 @@ static void NET_SV_ParseSYN(net_packet_t *packet, // Adopt the game mode and mission of the first connecting client - if (num_players == 0 && !cl_drone) + if (num_players == 0 && !data.drone) { - sv_gamemode = cl_gamemode; - sv_gamemission = cl_gamemission; + sv_gamemode = data.gamemode; + sv_gamemission = data.gamemission; } // Save the MD5 checksums @@ -607,7 +628,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet, // Check the connecting client is playing the same game as all // the other clients - if (cl_gamemode != sv_gamemode || cl_gamemission != sv_gamemission) + if (data.gamemode != sv_gamemode || data.gamemission != sv_gamemission) { NET_SV_SendReject(addr, "You are playing the wrong game!"); return; @@ -617,8 +638,8 @@ static void NET_SV_ParseSYN(net_packet_t *packet, NET_SV_InitNewClient(client, addr, player_name); - client->recording_lowres = cl_recording_lowres; - client->drone = cl_drone; + client->recording_lowres = data.lowres_turn; + client->drone = data.drone; } if (client->connection.state == NET_CONN_STATE_WAITING_ACK) @@ -681,6 +702,8 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) } } + settings.num_players = NET_SV_NumPlayers(); + nowtime = I_GetTimeMS(); // Send start packets to each connected node @@ -695,8 +718,8 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) startpacket = NET_Conn_NewReliable(&clients[i].connection, NET_PACKET_TYPE_GAMESTART); - NET_WriteInt8(startpacket, NET_SV_NumPlayers()); - NET_WriteInt8(startpacket, clients[i].player_number); + settings.consoleplayer = clients[i].player_number; + NET_WriteSettings(startpacket, &settings); } @@ -1070,6 +1093,7 @@ void NET_SV_SendQueryResponse(net_addr_t *addr) { net_packet_t *reply; net_querydata_t querydata; + int p; // Version @@ -1089,9 +1113,22 @@ void NET_SV_SendQueryResponse(net_addr_t *addr) querydata.gamemode = sv_gamemode; querydata.gamemission = sv_gamemission; - // Server description. This is currently hard-coded. + //! + // @arg <name> + // + // When starting a network server, specify a name for the server. + // + + p = M_CheckParmWithArgs("-servername", 1); - querydata.description = "Chocolate Doom server"; + if (p > 0) + { + querydata.description = myargv[p + 1]; + } + else + { + querydata.description = "Unnamed server"; + } // Send it and we're done. @@ -1109,6 +1146,14 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr) net_client_t *client; unsigned int packet_type; + // Response from master server? + + if (addr != NULL && addr == master_server) + { + NET_Query_MasterResponse(packet); + return; + } + // Find which client this packet came from client = NET_SV_FindClient(addr); @@ -1514,6 +1559,32 @@ void NET_SV_Init(void) server_initialized = true; } +void NET_SV_RegisterWithMaster(void) +{ + //! + // When running a server, don't register with the global master server. + // + // @category net + // + + if (!M_CheckParm("-privateserver")) + { + master_server = NET_Query_ResolveMaster(server_context); + } + else + { + master_server = NULL; + } + + // Send request. + + if (master_server != NULL) + { + NET_Query_AddToMaster(master_server); + master_refresh_time = I_GetTimeMS(); + } +} + // Run server code to check for new packets/send packets as the server // requires @@ -1528,12 +1599,21 @@ void NET_SV_Run(void) return; } - while (NET_RecvPacket(server_context, &addr, &packet)) + while (NET_RecvPacket(server_context, &addr, &packet)) { NET_SV_Packet(packet, addr); NET_FreePacket(packet); } + // Possibly refresh our registration with the master server. + + if (master_server != NULL + && I_GetTimeMS() - master_refresh_time > MASTER_REFRESH_PERIOD * 1000) + { + NET_Query_AddToMaster(master_server); + master_refresh_time = I_GetTimeMS(); + } + // "Run" any clients that may have things to do, independent of responses // to received packets diff --git a/src/net_server.h b/src/net_server.h index 93b22fc3..1debbd79 100644 --- a/src/net_server.h +++ b/src/net_server.h @@ -41,5 +41,9 @@ void NET_SV_Shutdown(void); void NET_SV_AddModule(net_module_t *module); +// Register server with master server. + +void NET_SV_RegisterWithMaster(void); + #endif /* #ifndef NET_SERVER_H */ diff --git a/src/net_structrw.c b/src/net_structrw.c index 01933ebb..7380e334 100644 --- a/src/net_structrw.c +++ b/src/net_structrw.c @@ -30,6 +30,22 @@ #include "net_packet.h" #include "net_structrw.h" +void NET_WriteConnectData(net_packet_t *packet, net_connect_data_t *data) +{ + NET_WriteInt8(packet, data->gamemode); + NET_WriteInt8(packet, data->gamemission); + NET_WriteInt8(packet, data->lowres_turn); + NET_WriteInt8(packet, data->drone); +} + +boolean NET_ReadConnectData(net_packet_t *packet, net_connect_data_t *data) +{ + return NET_ReadInt8(packet, (unsigned int *) &data->gamemode) + && NET_ReadInt8(packet, (unsigned int *) &data->gamemission) + && NET_ReadInt8(packet, (unsigned int *) &data->lowres_turn) + && NET_ReadInt8(packet, (unsigned int *) &data->drone); +} + void NET_WriteSettings(net_packet_t *packet, net_gamesettings_t *settings) { NET_WriteInt8(packet, settings->ticdup); @@ -46,6 +62,8 @@ void NET_WriteSettings(net_packet_t *packet, net_gamesettings_t *settings) NET_WriteInt8(packet, settings->new_sync); NET_WriteInt32(packet, settings->timelimit); NET_WriteInt8(packet, settings->loadgame); + NET_WriteInt8(packet, settings->num_players); + NET_WriteInt8(packet, settings->consoleplayer); } boolean NET_ReadSettings(net_packet_t *packet, net_gamesettings_t *settings) @@ -63,7 +81,9 @@ boolean NET_ReadSettings(net_packet_t *packet, net_gamesettings_t *settings) && NET_ReadInt8(packet, (unsigned int *) &settings->lowres_turn) && NET_ReadInt8(packet, (unsigned int *) &settings->new_sync) && NET_ReadInt32(packet, (unsigned int *) &settings->timelimit) - && NET_ReadSInt8(packet, (signed int *) &settings->loadgame); + && NET_ReadSInt8(packet, (signed int *) &settings->loadgame) + && NET_ReadInt8(packet, (unsigned int *) &settings->num_players) + && NET_ReadSInt8(packet, (signed int *) &settings->consoleplayer); } boolean NET_ReadQueryData(net_packet_t *packet, net_querydata_t *query) diff --git a/src/net_structrw.h b/src/net_structrw.h index 13209778..68971cd3 100644 --- a/src/net_structrw.h +++ b/src/net_structrw.h @@ -26,6 +26,9 @@ #include "net_defs.h" #include "net_packet.h" +void NET_WriteConnectData(net_packet_t *packet, net_connect_data_t *data); +boolean NET_ReadConnectData(net_packet_t *packet, net_connect_data_t *data); + extern void NET_WriteSettings(net_packet_t *packet, net_gamesettings_t *settings); extern boolean NET_ReadSettings(net_packet_t *packet, net_gamesettings_t *settings); diff --git a/src/setup/display.c b/src/setup/display.c index 9fd0963b..f5f190f2 100644 --- a/src/setup/display.c +++ b/src/setup/display.c @@ -26,12 +26,40 @@ #include "libc_wince.h" #endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + #include "textscreen.h" #include "m_config.h" #include "mode.h" #include "display.h" +extern void RestartTextscreen(void); + +typedef struct +{ + char *description; + int bpp; +} pixel_depth_t; + +// List of supported pixel depths. + +static pixel_depth_t pixel_depths[] = +{ + { "8-bit", 8 }, + { "16-bit", 16 }, + { "24-bit", 24 }, + { "32-bit", 32 }, +}; + +// List of strings containing supported pixel depths. + +static char **supported_bpps; +static int num_supported_bpps; + typedef struct { int w, h; @@ -69,6 +97,7 @@ static screen_mode_t screen_modes_scaled[] = // List of fullscreen modes generated at runtime static screen_mode_t *screen_modes_fullscreen = NULL; +static int num_screen_modes_fullscreen; static int vidmode = 0; @@ -78,6 +107,7 @@ static int aspect_ratio_correct = 1; static int fullscreen = 1; static int screen_width = 320; static int screen_height = 200; +static int screen_bpp = 8; static int startup_delay = 1000; static int graphical_startup = 1; static int show_endoom = 1; @@ -90,6 +120,10 @@ static int usegamma = 0; static int selected_screen_width = 0, selected_screen_height; +// Index into the supported_bpps of the selected pixel depth. + +static int selected_bpp = 0; + static int system_video_env_set; // Set the SDL_VIDEODRIVER environment variable @@ -133,6 +167,153 @@ void SetDisplayDriver(void) } } +// Query SDL as to whether any fullscreen modes are available for the +// specified pixel depth. + +static int PixelDepthSupported(int bpp) +{ + SDL_PixelFormat format; + SDL_Rect **modes; + + format.BitsPerPixel = bpp; + format.BytesPerPixel = (bpp + 7) / 8; + + modes = SDL_ListModes(&format, SDL_FULLSCREEN); + + return modes != NULL; +} + +// Query SDL and populate the supported_bpps array. + +static void IdentifyPixelDepths(void) +{ + unsigned int i; + unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); + + if (supported_bpps != NULL) + { + free(supported_bpps); + } + + supported_bpps = malloc(sizeof(char *) * num_depths); + num_supported_bpps = 0; + + // Check each bit depth to determine if modes are available. + + for (i = 0; i < num_depths; ++i) + { + // If modes are available, add this bit depth to the list. + + if (PixelDepthSupported(pixel_depths[i].bpp)) + { + supported_bpps[num_supported_bpps] = pixel_depths[i].description; + ++num_supported_bpps; + } + } + + // No supported pixel depths? That's kind of a problem. Add 8bpp + // as a fallback. + + if (num_supported_bpps == 0) + { + supported_bpps[0] = pixel_depths[0].description; + ++num_supported_bpps; + } +} + +// Get the screen pixel depth corresponding to what selected_bpp is set to. + +static int GetSelectedBPP(void) +{ + unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); + unsigned int i; + + // Find which pixel depth is selected, and set screen_bpp. + + for (i = 0; i < num_depths; ++i) + { + if (pixel_depths[i].description == supported_bpps[selected_bpp]) + { + return pixel_depths[i].bpp; + } + } + + // Default fallback value. + + return 8; +} + +// Get the index into supported_bpps of the specified pixel depth string. + +static int GetSupportedBPPIndex(char *description) +{ + unsigned int i; + + for (i = 0; i < num_supported_bpps; ++i) + { + if (supported_bpps[i] == description) + { + return i; + } + } + + // Shouldn't happen; fall back to the first in the list. + + return 0; +} + +// Set selected_bpp to match screen_bpp. + +static int TrySetSelectedBPP(void) +{ + unsigned int num_depths = sizeof(pixel_depths) / sizeof(*pixel_depths); + unsigned int i; + + // Search pixel_depths, find the bpp that corresponds to screen_bpp, + // then set selected_bpp to match. + + for (i = 0; i < num_depths; ++i) + { + if (pixel_depths[i].bpp == screen_bpp) + { + selected_bpp = GetSupportedBPPIndex(pixel_depths[i].description); + return 1; + } + } + + return 0; +} + +static void SetSelectedBPP(void) +{ + const SDL_VideoInfo *info; + + if (TrySetSelectedBPP()) + { + return; + } + + // screen_bpp does not match any supported pixel depth. Query SDL + // to find out what it recommends using. + + info = SDL_GetVideoInfo(); + + if (info != NULL && info->vfmt != NULL) + { + screen_bpp = info->vfmt->BitsPerPixel; + } + + // Try again. + + if (!TrySetSelectedBPP()) + { + // Give up and just use the first in the list. + + selected_bpp = 0; + screen_bpp = GetSelectedBPP(); + } +} + static void ModeSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(mode)) { TXT_CAST_ARG(screen_mode_t, mode); @@ -177,6 +358,7 @@ static int GoodFullscreenMode(screen_mode_t *mode) static void BuildFullscreenModesList(void) { + SDL_PixelFormat format; SDL_Rect **modes; screen_mode_t *m1; screen_mode_t *m2; @@ -194,7 +376,10 @@ static void BuildFullscreenModesList(void) // Get a list of fullscreen modes and find out how many // modes are in the list. - modes = SDL_ListModes(NULL, SDL_FULLSCREEN); + format.BitsPerPixel = screen_bpp; + format.BytesPerPixel = (screen_bpp + 7) / 8; + + modes = SDL_ListModes(&format, SDL_FULLSCREEN); if (modes == NULL || modes == (SDL_Rect **) -1) { @@ -229,6 +414,8 @@ static void BuildFullscreenModesList(void) memcpy(m1, m2, sizeof(screen_mode_t)); memcpy(m2, &m, sizeof(screen_mode_t)); } + + num_screen_modes_fullscreen = num_modes; } static int FindBestMode(screen_mode_t *modes) @@ -295,7 +482,7 @@ static void GenerateModesTable(TXT_UNCAST_ARG(widget), // Build the table TXT_ClearTable(modes_table); - TXT_SetColumnWidths(modes_table, 15, 15, 15); + TXT_SetColumnWidths(modes_table, 14, 14, 14, 14, 14); for (i=0; modes[i].w != 0; ++i) { @@ -317,8 +504,25 @@ static void GenerateModesTable(TXT_UNCAST_ARG(widget), vidmode = FindBestMode(modes); - screen_width = modes[vidmode].w; - screen_height = modes[vidmode].h; + if (vidmode > 0) + { + screen_width = modes[vidmode].w; + screen_height = modes[vidmode].h; + } +} + +// Callback invoked when the BPP selector is changed. + +static void UpdateBPP(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(modes_table)) +{ + TXT_CAST_ARG(txt_table_t, modes_table); + + screen_bpp = GetSelectedBPP(); + + // Rebuild list of fullscreen modes. + + BuildFullscreenModesList(); + GenerateModesTable(NULL, modes_table); } #if defined(_WIN32) && !defined(_WIN32_WCE) @@ -331,18 +535,6 @@ static char *win32_video_drivers[] = "Windows GDI", }; -// Restart the textscreen library. Used when the video_driver variable -// is changed. - -static void RestartTextscreen(void) -{ - TXT_Shutdown(); - - SetDisplayDriver(); - - TXT_Init(); -} - static void SetWin32VideoDriver(void) { if (!strcmp(video_driver, "windib")) @@ -372,6 +564,11 @@ static void UpdateVideoDriver(TXT_UNCAST_ARG(widget), RestartTextscreen(); + // Rebuild the list of supported pixel depths. + + IdentifyPixelDepths(); + SetSelectedBPP(); + // Rebuild the video modes list BuildFullscreenModesList(); @@ -385,8 +582,18 @@ void ConfigDisplay(void) { txt_window_t *window; txt_table_t *modes_table; + txt_table_t *bpp_table; txt_checkbox_t *fs_checkbox; txt_checkbox_t *ar_checkbox; + txt_dropdown_list_t *bpp_selector; + int num_columns; + int window_y; + + // What color depths are supported? Generate supported_bpps array + // and set selected_bpp to match the current value of screen_bpp. + + IdentifyPixelDepths(); + SetSelectedBPP(); // First time in? Initialise selected_screen_{width,height} @@ -400,16 +607,43 @@ void ConfigDisplay(void) window = TXT_NewWindow("Display Configuration"); - TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP, - TXT_SCREEN_W / 2, 5); - TXT_AddWidgets(window, fs_checkbox = TXT_NewCheckBox("Fullscreen", &fullscreen), ar_checkbox = TXT_NewCheckBox("Correct aspect ratio", &aspect_ratio_correct), NULL); - modes_table = TXT_NewTable(3); + // Some machines can have lots of video modes. This tries to + // keep a limit of six lines by increasing the number of + // columns. In extreme cases, the window is moved up slightly. + + BuildFullscreenModesList(); + + window_y = 5; + + if (num_screen_modes_fullscreen <= 18) + { + num_columns = 3; + } + else if (num_screen_modes_fullscreen <= 24) + { + num_columns = 4; + } + else + { + num_columns = 5; + window_y -= 3; + } + + modes_table = TXT_NewTable(num_columns); + + // The window is set at a fixed vertical position. This keeps + // the top of the window stationary when switching between + // fullscreen and windowed mode (which causes the window's + // height to change). + + TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP, + TXT_SCREEN_W / 2, window_y); // On Windows, there is an extra control to change between // the Windows GDI and DirectX video drivers. @@ -442,6 +676,7 @@ void ConfigDisplay(void) TXT_AddWidgets(window, TXT_NewSeparator("Screen mode"), + bpp_table = TXT_NewTable(2), modes_table, TXT_NewSeparator("Misc."), NULL); @@ -458,6 +693,15 @@ void ConfigDisplay(void) TXT_NewCheckBox("Show ENDOOM screen", &show_endoom)); } + TXT_AddWidgets(bpp_table, + TXT_NewLabel("Color depth: "), + bpp_selector = TXT_NewDropdownList(&selected_bpp, + supported_bpps, + num_supported_bpps), + NULL); + + + TXT_SignalConnect(bpp_selector, "changed", UpdateBPP, modes_table); TXT_SignalConnect(fs_checkbox, "changed", GenerateModesTable, modes_table); TXT_SignalConnect(ar_checkbox, "changed", GenerateModesTable, modes_table); @@ -486,5 +730,25 @@ void BindDisplayVariables(void) M_BindVariable("graphical_startup", &graphical_startup); } + // Windows Vista or later? Set screen color depth to + // 32 bits per pixel, as 8-bit palettized screen modes + // don't work properly in recent versions. + +#if defined(_WIN32) && !defined(_WIN32_WCE) + { + OSVERSIONINFOEX version_info; + + ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); + version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + GetVersionEx((OSVERSIONINFO *) &version_info); + + if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT + && version_info.dwMajorVersion >= 6) + { + screen_bpp = 32; + } + } +#endif } diff --git a/src/setup/execute.c b/src/setup/execute.c index 4be44149..f85b8af4 100644 --- a/src/setup/execute.c +++ b/src/setup/execute.c @@ -88,6 +88,42 @@ static char *TempFile(char *s) return result; } +static int ArgumentNeedsEscape(char *arg) +{ + char *p; + + for (p = arg; *p != '\0'; ++p) + { + if (isspace(*p)) + { + return 1; + } + } + + return 0; +} + +// Arguments passed to the setup tool should be passed through to the +// game when launching a game. Calling this adds all arguments from +// myargv to the output context. + +void PassThroughArguments(execute_context_t *context) +{ + int i; + + for (i = 1; i < myargc; ++i) + { + if (ArgumentNeedsEscape(myargv[i])) + { + AddCmdLineParameter(context, "\"%s\"", myargv[i]); + } + else + { + AddCmdLineParameter(context, "%s", myargv[i]); + } + } +} + execute_context_t *NewExecuteContext(void) { execute_context_t *result; @@ -106,25 +142,6 @@ execute_context_t *NewExecuteContext(void) return result; } -void AddConfigParameters(execute_context_t *context) -{ - int p; - - p = M_CheckParm("-config"); - - if (p > 0) - { - AddCmdLineParameter(context, "-config \"%s\"", myargv[p + 1]); - } - - p = M_CheckParm("-extraconfig"); - - if (p > 0) - { - AddCmdLineParameter(context, "-extraconfig \"%s\"", myargv[p + 1]); - } -} - void AddCmdLineParameter(execute_context_t *context, char *s, ...) { va_list args; diff --git a/src/setup/execute.h b/src/setup/execute.h index 24711a16..25f1f10a 100644 --- a/src/setup/execute.h +++ b/src/setup/execute.h @@ -35,7 +35,7 @@ typedef struct execute_context_s execute_context_t; execute_context_t *NewExecuteContext(void); void AddCmdLineParameter(execute_context_t *context, char *s, ...); -void AddConfigParameters(execute_context_t *context); +void PassThroughArguments(execute_context_t *context); int ExecuteDoom(execute_context_t *context); int FindInstalledIWADs(void); diff --git a/src/setup/joystick.c b/src/setup/joystick.c index fbe3a3f3..0fc00ea1 100644 --- a/src/setup/joystick.c +++ b/src/setup/joystick.c @@ -65,8 +65,8 @@ static int joystick_y_invert = 0; static txt_button_t *joystick_button; static int *all_joystick_buttons[] = { - &joybstraferight, &joybstrafeleft, &joybfire, &joybspeed, - &joybuse, &joybstrafe, &joybjump + &joybstraferight, &joybstrafeleft, &joybfire, &joybspeed, + &joybuse, &joybstrafe, &joybprevweapon, &joybnextweapon, &joybjump }; // diff --git a/src/setup/mainmenu.c b/src/setup/mainmenu.c index c3cb7db5..55496010 100644 --- a/src/setup/mainmenu.c +++ b/src/setup/mainmenu.c @@ -156,7 +156,7 @@ static void LaunchDoom(void *unused1, void *unused2) // Launch Doom exec = NewExecuteContext(); - AddConfigParameters(exec); + PassThroughArguments(exec); ExecuteDoom(exec); exit(0); @@ -189,6 +189,7 @@ void MainMenu(void) { txt_window_t *window; txt_window_action_t *quit_action; + txt_window_action_t *warp_action; window = TXT_NewWindow("Main Menu"); @@ -230,8 +231,12 @@ void MainMenu(void) NULL); quit_action = TXT_NewWindowAction(KEY_ESCAPE, "Quit"); + warp_action = TXT_NewWindowAction(KEY_F1, "Warp"); TXT_SignalConnect(quit_action, "pressed", QuitConfirm, NULL); + TXT_SignalConnect(warp_action, "pressed", + (TxtWidgetSignalFunc) WarpMenu, NULL); TXT_SetWindowAction(window, TXT_HORIZ_LEFT, quit_action); + TXT_SetWindowAction(window, TXT_HORIZ_CENTER, warp_action); TXT_SetKeyListener(window, MainMenuKeyPress, NULL); } @@ -292,11 +297,9 @@ static void SetIcon(void) free(mask); } -// -// Initialize and run the textscreen GUI. -// +// Initialize the textscreen library. -static void RunGUI(void) +static void InitTextscreen(void) { SetDisplayDriver(); @@ -308,6 +311,24 @@ static void RunGUI(void) TXT_SetDesktopTitle(PACKAGE_NAME " Setup ver " PACKAGE_VERSION); SetIcon(); +} + +// Restart the textscreen library. Used when the video_driver variable +// is changed. + +void RestartTextscreen(void) +{ + TXT_Shutdown(); + InitTextscreen(); +} + +// +// Initialize and run the textscreen GUI. +// + +static void RunGUI(void) +{ + InitTextscreen(); TXT_GUIMainLoop(); } diff --git a/src/setup/multiplayer.c b/src/setup/multiplayer.c index 24cd0670..aed89212 100644 --- a/src/setup/multiplayer.c +++ b/src/setup/multiplayer.c @@ -70,10 +70,10 @@ static char *iwadfile; static char *doom_skills[] = { - "I'm too young to die!", + "I'm too young to die.", "Hey, not too rough.", "Hurt me plenty.", - "Ultra-violence", + "Ultra-Violence.", "NIGHTMARE!", }; @@ -144,6 +144,7 @@ static int fast = 0; static int respawn = 0; static int udpport = 2342; static int timer = 0; +static int privateserver = 0; static txt_dropdown_list_t *skillbutton; static txt_button_t *warpbutton; @@ -209,7 +210,11 @@ static void AddIWADParameter(execute_context_t *exec) } } -static void StartGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) +// Callback function invoked to launch the game. +// This is used when starting a server and also when starting a +// single player game via the "warp" menu. + +static void StartGame(int multiplayer) { execute_context_t *exec; @@ -221,7 +226,6 @@ static void StartGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) AddExtraParameters(exec); AddIWADParameter(exec); - AddCmdLineParameter(exec, "-server"); AddCmdLineParameter(exec, "-skill %i", skill + 1); if (gamemission == hexen) @@ -244,20 +248,6 @@ static void StartGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) AddCmdLineParameter(exec, "-respawn"); } - if (deathmatch == 1) - { - AddCmdLineParameter(exec, "-deathmatch"); - } - else if (deathmatch == 2) - { - AddCmdLineParameter(exec, "-altdeath"); - } - - if (timer > 0) - { - AddCmdLineParameter(exec, "-timer %i", timer); - } - if (warptype == WARP_ExMy) { // TODO: select IWAD based on warp type @@ -268,20 +258,55 @@ static void StartGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(user_data)) AddCmdLineParameter(exec, "-warp %i", warpmap); } - AddCmdLineParameter(exec, "-port %i", udpport); + // Multiplayer-specific options: + + if (multiplayer) + { + AddCmdLineParameter(exec, "-server"); + AddCmdLineParameter(exec, "-port %i", udpport); + + if (deathmatch == 1) + { + AddCmdLineParameter(exec, "-deathmatch"); + } + else if (deathmatch == 2) + { + AddCmdLineParameter(exec, "-altdeath"); + } + + if (timer > 0) + { + AddCmdLineParameter(exec, "-timer %i", timer); + } + + if (privateserver) + { + AddCmdLineParameter(exec, "-privateserver"); + } + } AddWADs(exec); TXT_Shutdown(); M_SaveDefaults(); - AddConfigParameters(exec); + PassThroughArguments(exec); ExecuteDoom(exec); exit(0); } +static void StartServerGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + StartGame(1); +} + +static void StartSinglePlayerGame(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused)) +{ + StartGame(0); +} + static void UpdateWarpButton(void) { char buf[10]; @@ -544,12 +569,27 @@ static txt_widget_t *IWADSelector(void) return result; } -static txt_window_action_t *StartGameAction(void) +// Create the window action button to start the game. This invokes +// a different callback depending on whether to start a multiplayer +// or single player game. + +static txt_window_action_t *StartGameAction(int multiplayer) { txt_window_action_t *action; + TxtWidgetSignalFunc callback; action = TXT_NewWindowAction(KEY_F10, "Start"); - TXT_SignalConnect(action, "pressed", StartGame, NULL); + + if (multiplayer) + { + callback = StartServerGame; + } + else + { + callback = StartSinglePlayerGame; + } + + TXT_SignalConnect(action, "pressed", callback, NULL); return action; } @@ -591,7 +631,11 @@ static txt_window_action_t *WadWindowAction(void) return action; } -void StartMultiGame(void) +// "Start game" menu. This is used for the start server window +// and the single player warp menu. The parameters specify +// the window title and whether to display multiplayer options. + +static void StartGameMenu(char *window_title, int multiplayer) { txt_window_t *window; txt_table_t *gameopt_table; @@ -599,7 +643,7 @@ void StartMultiGame(void) txt_widget_t *iwad_selector; int num_mult_types = 2; - window = TXT_NewWindow("Start multiplayer game"); + window = TXT_NewWindow(window_title); TXT_AddWidgets(window, gameopt_table = TXT_NewTable(2), @@ -609,14 +653,12 @@ void StartMultiGame(void) TXT_NewCheckBox("Respawning monsters", &respawn), TXT_NewSeparator("Advanced"), advanced_table = TXT_NewTable(2), - TXT_NewButton2("Add extra parameters...", - OpenExtraParamsWindow, NULL), NULL); TXT_SetWindowAction(window, TXT_HORIZ_CENTER, WadWindowAction()); - TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, StartGameAction()); + TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, StartGameAction(multiplayer)); - TXT_SetColumnWidths(gameopt_table, 12, 12); + TXT_SetColumnWidths(gameopt_table, 12, 6); if (gamemission == doom) { @@ -632,14 +674,8 @@ void StartMultiGame(void) iwad_selector = IWADSelector(), TXT_NewLabel("Skill"), skillbutton = TXT_NewDropdownList(&skill, doom_skills, 5), - TXT_NewLabel("Game type"), - TXT_NewDropdownList(&deathmatch, gamemodes, num_mult_types), TXT_NewLabel("Level warp"), warpbutton = TXT_NewButton2("????", LevelSelectDialog, NULL), - TXT_NewLabel("Time limit"), - TXT_NewHorizBox(TXT_NewIntInputBox(&timer, 2), - TXT_NewLabel("minutes"), - NULL), NULL); if (gamemission == hexen) @@ -651,19 +687,49 @@ void StartMultiGame(void) NULL); } - TXT_SetColumnWidths(advanced_table, 12, 12); + if (multiplayer) + { + TXT_AddWidgets(gameopt_table, + TXT_NewLabel("Game type"), + TXT_NewDropdownList(&deathmatch, gamemodes, num_mult_types), + TXT_NewLabel("Time limit"), + TXT_NewHorizBox(TXT_NewIntInputBox(&timer, 2), + TXT_NewLabel("minutes"), + NULL), + NULL); + + TXT_AddWidget(window, + TXT_NewInvertedCheckBox("Register with master server", + &privateserver)); + + TXT_AddWidgets(advanced_table, + TXT_NewLabel("UDP port"), + TXT_NewIntInputBox(&udpport, 5), + NULL); + } - TXT_SignalConnect(iwad_selector, "changed", UpdateWarpType, NULL); + TXT_AddWidget(window, + TXT_NewButton2("Add extra parameters...", + OpenExtraParamsWindow, NULL)); - TXT_AddWidgets(advanced_table, - TXT_NewLabel("UDP port"), - TXT_NewIntInputBox(&udpport, 5), - NULL); + TXT_SetColumnWidths(advanced_table, 12, 6); + + TXT_SignalConnect(iwad_selector, "changed", UpdateWarpType, NULL); UpdateWarpType(NULL, NULL); UpdateWarpButton(); } +void StartMultiGame(void) +{ + StartGameMenu("Start multiplayer game", 1); +} + +void WarpMenu(void) +{ + StartGameMenu("Level Warp", 0); +} + static void DoJoinGame(void *unused1, void *unused2) { execute_context_t *exec; @@ -695,7 +761,7 @@ static void DoJoinGame(void *unused1, void *unused2) M_SaveDefaults(); - AddConfigParameters(exec); + PassThroughArguments(exec); ExecuteDoom(exec); diff --git a/src/setup/multiplayer.h b/src/setup/multiplayer.h index 7490bc3c..afc8a2a8 100644 --- a/src/setup/multiplayer.h +++ b/src/setup/multiplayer.h @@ -23,6 +23,7 @@ #define SETUP_MULTIPLAYER_H void StartMultiGame(void); +void WarpMenu(void); void JoinMultiGame(void); void MultiplayerConfig(void); diff --git a/src/setup/txt_joybinput.c b/src/setup/txt_joybinput.c index 1e132962..cde3d2c2 100644 --- a/src/setup/txt_joybinput.c +++ b/src/setup/txt_joybinput.c @@ -206,6 +206,7 @@ static void TXT_JoystickInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, in txt_widget_class_t txt_joystick_input_class = { + TXT_AlwaysSelectable, TXT_JoystickInputSizeCalc, TXT_JoystickInputDrawer, TXT_JoystickInputKeyPress, diff --git a/src/setup/txt_keyinput.c b/src/setup/txt_keyinput.c index 483c325f..08eb9d8c 100644 --- a/src/setup/txt_keyinput.c +++ b/src/setup/txt_keyinput.c @@ -171,6 +171,7 @@ static void TXT_KeyInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b) txt_widget_class_t txt_key_input_class = { + TXT_AlwaysSelectable, TXT_KeyInputSizeCalc, TXT_KeyInputDrawer, TXT_KeyInputKeyPress, diff --git a/src/setup/txt_mouseinput.c b/src/setup/txt_mouseinput.c index 8b87e651..4f454c8c 100644 --- a/src/setup/txt_mouseinput.c +++ b/src/setup/txt_mouseinput.c @@ -164,6 +164,7 @@ static void TXT_MouseInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b txt_widget_class_t txt_mouse_input_class = { + TXT_AlwaysSelectable, TXT_MouseInputSizeCalc, TXT_MouseInputDrawer, TXT_MouseInputKeyPress, diff --git a/src/strife/d_main.c b/src/strife/d_main.c index 4260ca7d..95b1b643 100644 --- a/src/strife/d_main.c +++ b/src/strife/d_main.c @@ -126,8 +126,6 @@ int startmap; boolean autostart; int startloadgame; -FILE* debugfile; - boolean advancedemo; // villsa [STRIFE] workparm variable (similar to devparm?) @@ -475,14 +473,6 @@ void D_DoomLoop (void) if (demorecording) G_BeginRecording (); - if (M_CheckParm ("-debugfile")) - { - char filename[20]; - sprintf (filename,"debug%i.txt",consoleplayer); - printf ("debug output to: %s\n",filename); - debugfile = fopen (filename,"w"); - } - TryRunTics(); if(!showintro) // [STRIFE] @@ -745,7 +735,7 @@ void D_QuitGame(void) // These are from the original source: some of them are perhaps // not used in any dehacked patches -static char *banners[] = +static char *banners[] = { // strife1.wad: @@ -1040,9 +1030,9 @@ static void InitGameVersion(void) // "ultimate" and "final". // - p = M_CheckParm("-gameversion"); + p = M_CheckParmWithArgs("-gameversion", 1); - if (p > 0) + if (p) { for (i=0; gameversions[i].description != NULL; ++i) { @@ -1431,6 +1421,21 @@ void D_DoomMain (void) } //! + // @category net + // + // Query the Internet master server for a global list of active + // servers. + // + + if (M_CheckParm("-search")) + { + printf("\nSearching for servers on Internet ...\n"); + p = NET_MasterQuery(NET_QueryPrintCallback, NULL); + printf("\n%i server(s) found.\n", p); + exit(0); + } + + //! // @arg <address> // @category net // @@ -1438,11 +1443,12 @@ void D_DoomMain (void) // address. // - p = M_CheckParm("-query"); + p = M_CheckParmWithArgs("-query", 1); - if (p > 0) + if (p) { NET_QueryAddress(myargv[p+1]); + exit(0); } //! @@ -1451,8 +1457,13 @@ void D_DoomMain (void) // Search the local LAN for running servers. // - if (M_CheckParm("-search")) - NET_LANQuery(); + if (M_CheckParm("-localsearch")) + { + printf("\nSearching for servers on local LAN ...\n"); + p = NET_LANQuery(NET_QueryPrintCallback, NULL); + printf("\n%i server(s) found.\n", p); + exit(0); + } #endif @@ -1615,23 +1626,9 @@ void D_DoomMain (void) // add any files specified on the command line with -file wadfile // to the wad list // - // convenience hack to allow -wart e m to add a wad file - // prepend a tilde to the filename so wadfile will be reloadable - p = M_CheckParm ("-wart"); - if (p) - { - myargv[p][4] = 'p'; // big hack, change to -warp - // Map name handling. - // [STRIFE]: looks for f:/st/data - p = atoi (myargv[p+1]); - if (p<10) - sprintf (file,"~f:/st/data/map0%i.wad", p); - else - sprintf (file,"~f:/st/data/map%i.wad", p); - - D_AddFile (file); - } + // Debug: +// W_PrintDirectory(); //! // @arg <demo> @@ -1641,7 +1638,7 @@ void D_DoomMain (void) // Play back the demo named demo.lmp. // - p = M_CheckParm ("-playdemo"); + p = M_CheckParmWithArgs ("-playdemo", 1); if (!p) { @@ -1653,11 +1650,11 @@ void D_DoomMain (void) // Play back the demo named demo.lmp, determining the framerate // of the screen. // - p = M_CheckParm ("-timedemo"); + p = M_CheckParmWithArgs("-timedemo", 1); } - if (p && p < myargc-1) + if (p) { if (!strcasecmp(myargv[p+1] + strlen(myargv[p+1]) - 4, ".lmp")) { @@ -1746,9 +1743,9 @@ void D_DoomMain (void) // 0 disables all monsters. // - p = M_CheckParm ("-skill"); + p = M_CheckParmWithArgs("-skill", 1); - if (p && p < myargc-1) + if (p) { startskill = myargv[p+1][0]-'1'; autostart = true; @@ -1761,9 +1758,9 @@ void D_DoomMain (void) // Start playing on episode n (1-4) // - p = M_CheckParm ("-episode"); + p = M_CheckParmWithArgs("-episode", 1); - if (p && p < myargc-1) + if (p) { startepisode = myargv[p+1][0]-'0'; startmap = 1; @@ -1780,9 +1777,9 @@ void D_DoomMain (void) // For multiplayer games: exit each level after n minutes. // - p = M_CheckParm ("-timer"); + p = M_CheckParmWithArgs("-timer", 1); - if (p && p < myargc-1 && deathmatch) + if (p) { timelimit = atoi(myargv[p+1]); printf("timer: %i\n", timelimit); @@ -1797,10 +1794,8 @@ void D_DoomMain (void) p = M_CheckParm ("-avg"); - if (p && p < myargc-1 && deathmatch) + if (p) { - DEH_printf("Austin Virtual Gaming: Levels will end " - "after 20 minutes\n"); timelimit = 20; } @@ -1812,9 +1807,9 @@ void D_DoomMain (void) // (Doom 2) // - p = M_CheckParm ("-warp"); + p = M_CheckParmWithArgs("-warp", 1); - if (p && p < myargc-1) + if (p) { if (gamemode == commercial) startmap = atoi (myargv[p+1]); @@ -1858,9 +1853,9 @@ void D_DoomMain (void) // Load the game in slot s. // - p = M_CheckParm ("-loadgame"); + p = M_CheckParmWithArgs("-loadgame", 1); - if (p && p < myargc-1) + if (p) { startloadgame = atoi(myargv[p+1]); } @@ -1956,17 +1951,17 @@ void D_DoomMain (void) // Record a demo named x.lmp. // - p = M_CheckParm ("-record"); + p = M_CheckParmWithArgs("-record", 1); - if (p && p < myargc-1) + if (p) { G_RecordDemo (myargv[p+1]); autostart = true; } D_IntroTick(); // [STRIFE] - p = M_CheckParm ("-playdemo"); - if (p && p < myargc-1) + p = M_CheckParmWithArgs("-playdemo", 1); + if (p) { singledemo = true; // quit after one demo G_DeferedPlayDemo (demolumpname); @@ -1974,8 +1969,8 @@ void D_DoomMain (void) } D_IntroTick(); // [STRIFE] - p = M_CheckParm ("-timedemo"); - if (p && p < myargc-1) + p = M_CheckParmWithArgs("-timedemo", 1); + if (p) { G_TimeDemo (demolumpname); D_DoomLoop (); // never returns diff --git a/src/strife/d_net.c b/src/strife/d_net.c index 3480b0ad..7e1644e8 100644 --- a/src/strife/d_net.c +++ b/src/strife/d_net.c @@ -49,7 +49,6 @@ #include "net_sdl.h" #include "net_loop.h" - // // NETWORKING // @@ -292,6 +291,7 @@ void D_CheckNetGame (void) if (i > 0) { addr = NET_FindLANServer(); + NET_SV_RegisterWithMaster(); if (addr == NULL) { @@ -307,7 +307,7 @@ void D_CheckNetGame (void) // address. // - i = M_CheckParm("-connect"); + i = M_CheckParmWithArgs("-connect", 1); if (i > 0) { @@ -382,12 +382,22 @@ void D_CheckNetGame (void) // Show players here; the server might have specified a time limit - if (timelimit > 0) + if (timelimit > 0 && deathmatch) { - DEH_printf("Levels will end after %d minute", timelimit); - if (timelimit > 1) - printf("s"); - printf(".\n"); + // Gross hack to work like Vanilla: + + if (timelimit == 20 && M_CheckParm("-avg")) + { + DEH_printf("Austin Virtual Gaming: Levels will end " + "after 20 minutes\n"); + } + else + { + DEH_printf("Levels will end after %d minute", timelimit); + if (timelimit > 1) + printf("s"); + printf(".\n"); + } } } @@ -399,9 +409,6 @@ void D_CheckNetGame (void) // void D_QuitNetGame (void) { - if (debugfile) - fclose (debugfile); - #ifdef FEATURE_MULTIPLAYER NET_SV_Shutdown(); diff --git a/src/strife/doomstat.h b/src/strife/doomstat.h index ae513f78..8cb562b2 100644 --- a/src/strife/doomstat.h +++ b/src/strife/doomstat.h @@ -264,7 +264,6 @@ extern int maxammo[NUMAMMO]; // File handling stuff. extern char * savegamedir; extern char basedefault[1024]; -extern FILE* debugfile; // if true, load all graphics at level load extern boolean precache; diff --git a/src/strife/dstrings.h b/src/strife/dstrings.h index bdc6b2ce..d47fc1af 100644 --- a/src/strife/dstrings.h +++ b/src/strife/dstrings.h @@ -38,15 +38,6 @@ #define SAVEGAMENAME "doomsav" -// -// File locations, -// relative to current position. -// Path names are OS-sensitive. -// -#define DEVMAPS "devmaps" -#define DEVDATA "devdata" - - // QuitDOOM messages // 8 per each game type #define NUM_QUITMESSAGES 8 diff --git a/src/strife/g_game.c b/src/strife/g_game.c index b8496a5b..c9d49c18 100644 --- a/src/strife/g_game.c +++ b/src/strife/g_game.c @@ -138,7 +138,7 @@ int gametic; int levelstarttic; // gametic at level start int totalkills, /*totalitems,*/ totalsecret; // for intermission -char demoname[32]; +char *demoname; boolean demorecording; boolean longtics; // cph's doom 1.91 longtics hack boolean lowres_turn; // low resolution turning for longtics @@ -2280,8 +2280,8 @@ void G_RecordDemo (char* name) int maxsize; usergame = false; - strcpy (demoname, name); - strcat (demoname, ".lmp"); + demoname = Z_Malloc(strlen(name) + 5, PU_STATIC, NULL); + sprintf(demoname, "%s.lmp", name); maxsize = 0x20000; //! @@ -2292,8 +2292,8 @@ void G_RecordDemo (char* name) // Specify the demo buffer size (KiB) // - i = M_CheckParm ("-maxdemo"); - if (i && i<myargc-1) + i = M_CheckParmWithArgs("-maxdemo", 1); + if (i) maxsize = atoi(myargv[i+1])*1024; demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL); demoend = demobuffer + maxsize; @@ -2450,10 +2450,11 @@ void G_DoPlayDemo (void) // Play back a demo recorded in a netgame with a single player. // - if (playeringame[1] || M_CheckParm("-netdemo") > 0) - { - netgame = true; - netdemo = true; + if (playeringame[1] || M_CheckParm("-solo-net") > 0 + || M_CheckParm("-netdemo") > 0) + { + netgame = true; + netdemo = true; } // don't spend a lot of time in loadlevel diff --git a/src/strife/m_menu.c b/src/strife/m_menu.c index 92564e96..4d16e3e8 100644 --- a/src/strife/m_menu.c +++ b/src/strife/m_menu.c @@ -1679,23 +1679,23 @@ boolean M_Responder (event_t* ev) if (ev->type == ev_joystick && joywait < I_GetTime()) { - if (ev->data3 == -1) + if (ev->data3 < 0) { key = key_menu_up; joywait = I_GetTime() + 5; } - else if (ev->data3 == 1) + else if (ev->data3 > 0) { key = key_menu_down; joywait = I_GetTime() + 5; } - if (ev->data2 == -1) + if (ev->data2 < 0) { key = key_menu_left; joywait = I_GetTime() + 2; } - else if (ev->data2 == 1) + else if (ev->data2 > 0) { key = key_menu_right; joywait = I_GetTime() + 2; diff --git a/src/strife/p_map.c b/src/strife/p_map.c index 6a1d526d..c557f968 100644 --- a/src/strife/p_map.c +++ b/src/strife/p_map.c @@ -1628,7 +1628,7 @@ static void SpechitOverrun(line_t *ld) // Use the specified magic value when emulating spechit overruns. // - p = M_CheckParm("-spechit"); + p = M_CheckParmWithArgs("-spechit", 1); if (p > 0) { diff --git a/src/strife/p_spec.c b/src/strife/p_spec.c index af070d55..e26d9144 100644 --- a/src/strife/p_spec.c +++ b/src/strife/p_spec.c @@ -1713,9 +1713,9 @@ static void DonutOverrun(fixed_t *s3_floorheight, short *s3_floorpic, // system. The default (if this option is not specified) is to // emulate the behavior when running under Windows 98. - p = M_CheckParm("-donut"); + p = M_CheckParmWithArgs("-donut", 2); - if (p > 0 && p < myargc - 2) + if (p > 0) { // Dump of needed memory: (fixed_t)0000:0000 and (short)0000:0008 // @@ -1893,10 +1893,9 @@ void P_SpawnSpecials (void) if (W_CheckNumForName(DEH_String("texture2")) >= 0) episode = 2; - // See if -TIMER was specified. - if (timelimit > 0) + if (timelimit > 0 && deathmatch) { levelTimer = true; levelTimeCount = timelimit * 60 * TICRATE; diff --git a/src/strife/r_data.c b/src/strife/r_data.c index 043df348..46138c85 100644 --- a/src/strife/r_data.c +++ b/src/strife/r_data.c @@ -409,6 +409,7 @@ R_GetColumn static void GenerateTextureHashTable(void) { + texture_t **rover; int i; int key; @@ -425,12 +426,25 @@ static void GenerateTextureHashTable(void) textures[i]->index = i; - // Hook into hash table + // Vanilla Doom does a linear search of the texures array + // and stops at the first entry it finds. If there are two + // entries with the same name, the first one in the array + // wins. The new entry must therefore be added at the end + // of the hash chain, so that earlier entries win. key = W_LumpNameHash(textures[i]->name) % numtextures; - textures[i]->next = textures_hashtable[key]; - textures_hashtable[key] = textures[i]; + rover = &textures_hashtable[key]; + + while (*rover != NULL) + { + rover = &(*rover)->next; + } + + // Hook into hash table + + textures[i]->next = NULL; + *rover = textures[i]; } } diff --git a/src/w_main.c b/src/w_main.c index 92a394dd..ed285498 100644 --- a/src/w_main.c +++ b/src/w_main.c @@ -53,7 +53,7 @@ boolean W_ParseCommandLine(void) // into the main IWAD. Multiple files may be specified. // - p = M_CheckParm("-merge"); + p = M_CheckParmWithArgs("-merge", 1); if (p > 0) { @@ -81,7 +81,7 @@ boolean W_ParseCommandLine(void) // Simulates the behavior of NWT's -merge option. Multiple files // may be specified. - p = M_CheckParm("-nwtmerge"); + p = M_CheckParmWithArgs("-nwtmerge", 1); if (p > 0) { @@ -108,7 +108,7 @@ boolean W_ParseCommandLine(void) // the main IWAD directory. Multiple files may be specified. // - p = M_CheckParm("-af"); + p = M_CheckParmWithArgs("-af", 1); if (p > 0) { @@ -133,7 +133,7 @@ boolean W_ParseCommandLine(void) // into the main IWAD directory. Multiple files may be specified. // - p = M_CheckParm("-as"); + p = M_CheckParmWithArgs("-as", 1); if (p > 0) { @@ -156,7 +156,7 @@ boolean W_ParseCommandLine(void) // Equivalent to "-af <files> -as <files>". // - p = M_CheckParm("-aa"); + p = M_CheckParmWithArgs("-aa", 1); if (p > 0) { @@ -182,7 +182,7 @@ boolean W_ParseCommandLine(void) // Load the specified PWAD files. // - p = M_CheckParm ("-file"); + p = M_CheckParmWithArgs ("-file", 1); if (p) { // the parms after p are wadfile/lump names, diff --git a/textscreen/examples/guitest.c b/textscreen/examples/guitest.c index 5a931949..df79be2d 100644 --- a/textscreen/examples/guitest.c +++ b/textscreen/examples/guitest.c @@ -163,8 +163,8 @@ void Window2(void) { txt_window_t *window; txt_table_t *table; + txt_table_t *unselectable_table; txt_scrollpane_t *scrollpane; - int i; window = TXT_NewWindow("Another test"); TXT_SetWindowPosition(window, @@ -172,10 +172,13 @@ void Window2(void) TXT_VERT_TOP, TXT_SCREEN_W - 1, 1); - for (i=0; i<5; ++i) - { - TXT_AddWidget(window, TXT_NewButton("hello there blah blah blah blah")); - } + TXT_AddWidgets(window, + TXT_NewScrollPane(40, 1, + TXT_NewLabel("* Unselectable scroll pane *")), + unselectable_table = TXT_NewTable(1), + NULL); + + TXT_AddWidget(unselectable_table, TXT_NewLabel("* Unselectable table *")); TXT_AddWidget(window, TXT_NewSeparator("Input boxes")); table = TXT_NewTable(2); diff --git a/textscreen/txt_button.c b/textscreen/txt_button.c index a7a2d25a..85517b3d 100644 --- a/textscreen/txt_button.c +++ b/textscreen/txt_button.c @@ -96,6 +96,7 @@ static void TXT_ButtonMousePress(TXT_UNCAST_ARG(button), int x, int y, int b) txt_widget_class_t txt_button_class = { + TXT_AlwaysSelectable, TXT_ButtonSizeCalc, TXT_ButtonDrawer, TXT_ButtonKeyPress, diff --git a/textscreen/txt_checkbox.c b/textscreen/txt_checkbox.c index 0cb06bad..35c5739d 100644 --- a/textscreen/txt_checkbox.c +++ b/textscreen/txt_checkbox.c @@ -34,9 +34,9 @@ static void TXT_CheckBoxSizeCalc(TXT_UNCAST_ARG(checkbox)) { TXT_CAST_ARG(txt_checkbox_t, checkbox); - // Minimum width is the string length + two spaces for padding + // Minimum width is the string length + right-side space for padding - checkbox->widget.w = strlen(checkbox->label) + 6; + checkbox->widget.w = strlen(checkbox->label) + 5; checkbox->widget.h = 1; } @@ -50,7 +50,7 @@ static void TXT_CheckBoxDrawer(TXT_UNCAST_ARG(checkbox), int selected) TXT_BGColor(TXT_COLOR_BLUE, 0); TXT_FGColor(TXT_COLOR_BRIGHT_CYAN); - TXT_DrawString(" ("); + TXT_DrawString("("); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); @@ -76,7 +76,7 @@ static void TXT_CheckBoxDrawer(TXT_UNCAST_ARG(checkbox), int selected) TXT_DrawString(checkbox->label); - for (i=strlen(checkbox->label); i < w-6; ++i) + for (i=strlen(checkbox->label); i < w-5; ++i) { TXT_DrawString(" "); } @@ -117,6 +117,7 @@ static void TXT_CheckBoxMousePress(TXT_UNCAST_ARG(checkbox), int x, int y, int b txt_widget_class_t txt_checkbox_class = { + TXT_AlwaysSelectable, TXT_CheckBoxSizeCalc, TXT_CheckBoxDrawer, TXT_CheckBoxKeyPress, diff --git a/textscreen/txt_dropdown.c b/textscreen/txt_dropdown.c index efed8d67..c8103302 100644 --- a/textscreen/txt_dropdown.c +++ b/textscreen/txt_dropdown.c @@ -262,6 +262,7 @@ static void TXT_DropdownListMousePress(TXT_UNCAST_ARG(list), txt_widget_class_t txt_dropdown_list_class = { + TXT_AlwaysSelectable, TXT_DropdownListSizeCalc, TXT_DropdownListDrawer, TXT_DropdownListKeyPress, diff --git a/textscreen/txt_inputbox.c b/textscreen/txt_inputbox.c index 3e52bae9..852346f3 100644 --- a/textscreen/txt_inputbox.c +++ b/textscreen/txt_inputbox.c @@ -232,6 +232,7 @@ static void TXT_InputBoxMousePress(TXT_UNCAST_ARG(inputbox), txt_widget_class_t txt_inputbox_class = { + TXT_AlwaysSelectable, TXT_InputBoxSizeCalc, TXT_InputBoxDrawer, TXT_InputBoxKeyPress, @@ -242,6 +243,7 @@ txt_widget_class_t txt_inputbox_class = txt_widget_class_t txt_int_inputbox_class = { + TXT_AlwaysSelectable, TXT_InputBoxSizeCalc, TXT_InputBoxDrawer, TXT_IntInputBoxKeyPress, diff --git a/textscreen/txt_label.c b/textscreen/txt_label.c index 7ae29c3d..0deea803 100644 --- a/textscreen/txt_label.c +++ b/textscreen/txt_label.c @@ -104,6 +104,7 @@ static void TXT_LabelDestructor(TXT_UNCAST_ARG(label)) txt_widget_class_t txt_label_class = { + TXT_NeverSelectable, TXT_LabelSizeCalc, TXT_LabelDrawer, NULL, @@ -170,7 +171,6 @@ txt_label_t *TXT_NewLabel(char *text) label = malloc(sizeof(txt_label_t)); TXT_InitWidget(label, &txt_label_class); - label->widget.selectable = 0; label->label = NULL; label->lines = NULL; diff --git a/textscreen/txt_radiobutton.c b/textscreen/txt_radiobutton.c index 7ede7211..00c2c4fc 100644 --- a/textscreen/txt_radiobutton.c +++ b/textscreen/txt_radiobutton.c @@ -34,9 +34,9 @@ static void TXT_RadioButtonSizeCalc(TXT_UNCAST_ARG(radiobutton)) { TXT_CAST_ARG(txt_radiobutton_t, radiobutton); - // Minimum width is the string length + two spaces for padding + // Minimum width is the string length + right-side spaces for padding - radiobutton->widget.w = strlen(radiobutton->label) + 6; + radiobutton->widget.w = strlen(radiobutton->label) + 5; radiobutton->widget.h = 1; } @@ -50,7 +50,7 @@ static void TXT_RadioButtonDrawer(TXT_UNCAST_ARG(radiobutton), int selected) TXT_BGColor(TXT_COLOR_BLUE, 0); TXT_FGColor(TXT_COLOR_BRIGHT_CYAN); - TXT_DrawString(" ("); + TXT_DrawString("("); TXT_FGColor(TXT_COLOR_BRIGHT_WHITE); @@ -76,7 +76,7 @@ static void TXT_RadioButtonDrawer(TXT_UNCAST_ARG(radiobutton), int selected) TXT_DrawString(radiobutton->label); - for (i=strlen(radiobutton->label); i < w-6; ++i) + for (i=strlen(radiobutton->label); i < w-5; ++i) { TXT_DrawString(" "); } @@ -121,6 +121,7 @@ static void TXT_RadioButtonMousePress(TXT_UNCAST_ARG(radiobutton), txt_widget_class_t txt_radiobutton_class = { + TXT_AlwaysSelectable, TXT_RadioButtonSizeCalc, TXT_RadioButtonDrawer, TXT_RadioButtonKeyPress, diff --git a/textscreen/txt_scrollpane.c b/textscreen/txt_scrollpane.c index d81cce4b..17c9bcbf 100644 --- a/textscreen/txt_scrollpane.c +++ b/textscreen/txt_scrollpane.c @@ -138,7 +138,7 @@ static void TXT_ScrollPaneSizeCalc(TXT_UNCAST_ARG(scrollpane)) } if (scrollpane->expand_h) { - scrollpane->h = FullWidth(scrollpane); + scrollpane->h = FullHeight(scrollpane); } scrollpane->widget.w = scrollpane->w; @@ -486,8 +486,26 @@ static void TXT_ScrollPaneLayout(TXT_UNCAST_ARG(scrollpane)) } } +static int TXT_ScrollPaneSelectable(TXT_UNCAST_ARG(scrollpane)) +{ + TXT_CAST_ARG(txt_scrollpane_t, scrollpane); + + // If scroll bars are displayed, the scroll pane must be selectable + // so that we can use the arrow keys to scroll around. + + if (NeedsScrollbars(scrollpane)) + { + return 1; + } + + // Otherwise, whether this is selectable depends on the child widget. + + return TXT_SelectableWidget(scrollpane->child); +} + txt_widget_class_t txt_scrollpane_class = { + TXT_ScrollPaneSelectable, TXT_ScrollPaneSizeCalc, TXT_ScrollPaneDrawer, TXT_ScrollPaneKeyPress, diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c index a0cbe3d6..2fbaa316 100644 --- a/textscreen/txt_sdl.c +++ b/textscreen/txt_sdl.c @@ -119,6 +119,22 @@ static SDL_Color ega_colors[] = #endif +static txt_font_t *FontForName(char *name) +{ + if (!strcmp(name, "small")) + { + return &small_font; + } + else if (!strcmp(name, "normal")) + { + return &main_font; + } + else + { + return NULL; + } +} + // // Select the font to use, based on screen resolution // @@ -129,9 +145,22 @@ static SDL_Color ega_colors[] = static void ChooseFont(void) { SDL_Rect **modes; + char *env; int i; - font = &main_font; + // Allow normal selection to be overridden from an environment variable: + + env = getenv("TEXTSCREEN_FONT"); + + if (env != NULL) + { + font = FontForName(env); + + if (font != NULL) + { + return; + } + } // Check all modes @@ -140,6 +169,8 @@ static void ChooseFont(void) // If in doubt and we can't get a list, always prefer to // fall back to the normal font: + font = &main_font; + if (modes == NULL || modes == (SDL_Rect **) -1 || *modes == NULL) { #ifdef _WIN32_WCE @@ -357,10 +388,6 @@ static int TranslateKey(SDL_keysym *sym) case SDLK_PAUSE: return KEY_PAUSE; -#if !SDL_VERSION_ATLEAST(1, 3, 0) - case SDLK_EQUALS: return KEY_EQUALS; -#endif - case SDLK_LSHIFT: case SDLK_RSHIFT: return KEY_RSHIFT; diff --git a/textscreen/txt_separator.c b/textscreen/txt_separator.c index 2bf74b8f..6b779626 100644 --- a/textscreen/txt_separator.c +++ b/textscreen/txt_separator.c @@ -82,6 +82,7 @@ static void TXT_SeparatorDestructor(TXT_UNCAST_ARG(separator)) txt_widget_class_t txt_separator_class = { + TXT_NeverSelectable, TXT_SeparatorSizeCalc, TXT_SeparatorDrawer, NULL, @@ -97,7 +98,6 @@ txt_separator_t *TXT_NewSeparator(char *label) separator = malloc(sizeof(txt_separator_t)); TXT_InitWidget(separator, &txt_separator_class); - separator->widget.selectable = 0; if (label != NULL) { diff --git a/textscreen/txt_spinctrl.c b/textscreen/txt_spinctrl.c index 2b99f535..d775aecf 100644 --- a/textscreen/txt_spinctrl.c +++ b/textscreen/txt_spinctrl.c @@ -358,6 +358,7 @@ static void TXT_SpinControlMousePress(TXT_UNCAST_ARG(spincontrol), txt_widget_class_t txt_spincontrol_class = { + TXT_AlwaysSelectable, TXT_SpinControlSizeCalc, TXT_SpinControlDrawer, TXT_SpinControlKeyPress, diff --git a/textscreen/txt_strut.c b/textscreen/txt_strut.c index e7fe6328..f3a618f3 100644 --- a/textscreen/txt_strut.c +++ b/textscreen/txt_strut.c @@ -55,6 +55,7 @@ static int TXT_StrutKeyPress(TXT_UNCAST_ARG(strut), int key) txt_widget_class_t txt_strut_class = { + TXT_NeverSelectable, TXT_StrutSizeCalc, TXT_StrutDrawer, TXT_StrutKeyPress, @@ -70,7 +71,6 @@ txt_strut_t *TXT_NewStrut(int width, int height) strut = malloc(sizeof(txt_strut_t)); TXT_InitWidget(strut, &txt_strut_class); - strut->widget.selectable = 0; strut->width = width; strut->height = height; diff --git a/textscreen/txt_table.c b/textscreen/txt_table.c index 1b432681..ffe6fd14 100644 --- a/textscreen/txt_table.c +++ b/textscreen/txt_table.c @@ -202,7 +202,7 @@ void TXT_AddWidgets(TXT_UNCAST_ARG(table), ...) va_end(args); } -static int SelectableWidget(txt_table_t *table, int x, int y) +static int SelectableCell(txt_table_t *table, int x, int y) { txt_widget_t *widget; int i; @@ -217,7 +217,9 @@ static int SelectableWidget(txt_table_t *table, int x, int y) if (i >= 0 && i < table->num_widgets) { widget = table->widgets[i]; - return widget != NULL && widget->selectable && widget->visible; + return widget != NULL + && TXT_SelectableWidget(widget) + && widget->visible; } return 0; @@ -237,14 +239,14 @@ static int FindSelectableColumn(txt_table_t *table, int row, int start_col) { // Search to the right - if (SelectableWidget(table, start_col + x, row)) + if (SelectableCell(table, start_col + x, row)) { return start_col + x; } // Search to the left - if (SelectableWidget(table, start_col - x, row)) + if (SelectableCell(table, start_col - x, row)) { return start_col - x; } @@ -270,7 +272,7 @@ static int TXT_TableKeyPress(TXT_UNCAST_ARG(table), int key) if (selected >= 0 && selected < table->num_widgets) { if (table->widgets[selected] != NULL - && table->widgets[selected]->selectable + && TXT_SelectableWidget(table->widgets[selected]) && TXT_WidgetKeyPress(table->widgets[selected], key)) { return 1; @@ -329,7 +331,7 @@ static int TXT_TableKeyPress(TXT_UNCAST_ARG(table), int key) for (new_x = table->selected_x - 1; new_x >= 0; --new_x) { - if (SelectableWidget(table, new_x, table->selected_y)) + if (SelectableCell(table, new_x, table->selected_y)) { // Found a selectable widget! @@ -348,7 +350,7 @@ static int TXT_TableKeyPress(TXT_UNCAST_ARG(table), int key) for (new_x = table->selected_x + 1; new_x < table->columns; ++new_x) { - if (SelectableWidget(table, new_x, table->selected_y)) + if (SelectableCell(table, new_x, table->selected_y)) { // Found a selectable widget! @@ -547,7 +549,7 @@ static void TXT_TableMousePress(TXT_UNCAST_ARG(table), int x, int y, int b) // Select the cell if the widget is selectable - if (widget->selectable) + if (TXT_SelectableWidget(widget)) { table->selected_x = i % table->columns; table->selected_y = i / table->columns; @@ -563,8 +565,41 @@ static void TXT_TableMousePress(TXT_UNCAST_ARG(table), int x, int y, int b) } } +// Determine whether the table is selectable. + +static int TXT_TableSelectable(TXT_UNCAST_ARG(table)) +{ + TXT_CAST_ARG(txt_table_t, table); + int i; + + // Is the currently-selected cell selectable? + + if (SelectableCell(table, table->selected_x, table->selected_y)) + { + return 1; + } + + // Find the first selectable cell and set selected_x, selected_y. + + for (i = 0; i < table->num_widgets; ++i) + { + if (table->widgets[i] != NULL + && TXT_SelectableWidget(table->widgets[i])) + { + table->selected_x = i % table->columns; + table->selected_y = i / table->columns; + return 1; + } + } + + // No selectable widgets exist within the table. + + return 0; +} + txt_widget_class_t txt_table_class = { + TXT_TableSelectable, TXT_CalcTableSize, TXT_TableDrawer, TXT_TableKeyPress, diff --git a/textscreen/txt_widget.c b/textscreen/txt_widget.c index 2300b32c..760943d5 100644 --- a/textscreen/txt_widget.c +++ b/textscreen/txt_widget.c @@ -83,9 +83,8 @@ void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class) widget->widget_class = widget_class; widget->callback_table = TXT_NewCallbackTable(); - // Default values: visible and selectable + // Visible by default. - widget->selectable = 1; widget->visible = 1; // Align left by default @@ -214,3 +213,27 @@ void TXT_LayoutWidget(TXT_UNCAST_ARG(widget)) } } +int TXT_AlwaysSelectable(TXT_UNCAST_ARG(widget)) +{ + return 1; +} + +int TXT_NeverSelectable(TXT_UNCAST_ARG(widget)) +{ + return 0; +} + +int TXT_SelectableWidget(TXT_UNCAST_ARG(widget)) +{ + TXT_CAST_ARG(txt_widget_t, widget); + + if (widget->widget_class->selectable != NULL) + { + return widget->widget_class->selectable(widget); + } + else + { + return 0; + } +} + diff --git a/textscreen/txt_widget.h b/textscreen/txt_widget.h index 9688829d..bb895f92 100644 --- a/textscreen/txt_widget.h +++ b/textscreen/txt_widget.h @@ -77,9 +77,11 @@ typedef int (*TxtWidgetKeyPress)(TXT_UNCAST_ARG(widget), int key); typedef void (*TxtWidgetSignalFunc)(TXT_UNCAST_ARG(widget), void *user_data); typedef void (*TxtMousePressFunc)(TXT_UNCAST_ARG(widget), int x, int y, int b); typedef void (*TxtWidgetLayoutFunc)(TXT_UNCAST_ARG(widget)); +typedef int (*TxtWidgetSelectableFunc)(TXT_UNCAST_ARG(widget)); struct txt_widget_class_s { + TxtWidgetSelectableFunc selectable; TxtWidgetSizeCalc size_calc; TxtWidgetDrawer drawer; TxtWidgetKeyPress key_press; @@ -92,7 +94,6 @@ struct txt_widget_s { txt_widget_class_t *widget_class; txt_callback_table_t *callback_table; - int selectable; int visible; txt_horiz_align_t align; @@ -111,6 +112,8 @@ int TXT_WidgetKeyPress(TXT_UNCAST_ARG(widget), int key); void TXT_WidgetMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b); void TXT_DestroyWidget(TXT_UNCAST_ARG(widget)); void TXT_LayoutWidget(TXT_UNCAST_ARG(widget)); +int TXT_AlwaysSelectable(TXT_UNCAST_ARG(widget)); +int TXT_NeverSelectable(TXT_UNCAST_ARG(widget)); /** * Set a callback function to be invoked when a signal occurs. @@ -134,6 +137,15 @@ void TXT_SignalConnect(TXT_UNCAST_ARG(widget), const char *signal_name, void TXT_SetWidgetAlign(TXT_UNCAST_ARG(widget), txt_horiz_align_t horiz_align); +/** + * Query whether a widget is selectable with the cursor. + * + * @param widget The widget. + * @return Non-zero if the widget is selectable. + */ + +int TXT_SelectableWidget(TXT_UNCAST_ARG(widget)); + #endif /* #ifndef TXT_WIDGET_H */ diff --git a/textscreen/txt_window.c b/textscreen/txt_window.c index 33f53d4a..46e71d3a 100644 --- a/textscreen/txt_window.c +++ b/textscreen/txt_window.c @@ -140,6 +140,15 @@ static void CalcWindowPosition(txt_window_t *window) static void LayoutActionArea(txt_window_t *window) { txt_widget_t *widget; + int space_available; + int space_left_offset; + + // We need to calculate the available horizontal space for the center + // action widget, so that we can center it within it. + // To start with, we have the entire action area available. + + space_available = window->window_w; + space_left_offset = 0; // Left action @@ -151,29 +160,43 @@ static void LayoutActionArea(txt_window_t *window) widget->x = window->window_x + 2; widget->y = window->window_y + window->window_h - widget->h - 1; + + // Adjust available space: + + space_available -= widget->w; + space_left_offset += widget->w; } - // Draw the center action + // Draw the right action - if (window->actions[TXT_HORIZ_CENTER] != NULL) + if (window->actions[TXT_HORIZ_RIGHT] != NULL) { - widget = (txt_widget_t *) window->actions[TXT_HORIZ_CENTER]; + widget = (txt_widget_t *) window->actions[TXT_HORIZ_RIGHT]; TXT_CalcWidgetSize(widget); - widget->x = window->window_x + (window->window_w - widget->w - 2) / 2; + widget->x = window->window_x + window->window_w - 2 - widget->w; widget->y = window->window_y + window->window_h - widget->h - 1; + + // Adjust available space: + + space_available -= widget->w; } - // Draw the right action + // Draw the center action - if (window->actions[TXT_HORIZ_RIGHT] != NULL) + if (window->actions[TXT_HORIZ_CENTER] != NULL) { - widget = (txt_widget_t *) window->actions[TXT_HORIZ_RIGHT]; + widget = (txt_widget_t *) window->actions[TXT_HORIZ_CENTER]; TXT_CalcWidgetSize(widget); - widget->x = window->window_x + window->window_w - 2 - widget->w; + // The left and right widgets have left a space sandwiched between + // them. Center this widget within that space. + + widget->x = window->window_x + + space_left_offset + + (space_available - widget->w) / 2; widget->y = window->window_y + window->window_h - widget->h - 1; } } diff --git a/textscreen/txt_window_action.c b/textscreen/txt_window_action.c index a326a5ed..e593b7b6 100644 --- a/textscreen/txt_window_action.c +++ b/textscreen/txt_window_action.c @@ -93,6 +93,7 @@ static void TXT_WindowActionMousePress(TXT_UNCAST_ARG(action), txt_widget_class_t txt_window_action_class = { + TXT_AlwaysSelectable, TXT_WindowActionSizeCalc, TXT_WindowActionDrawer, TXT_WindowActionKeyPress, |